Merge from rustc

This commit is contained in:
The rustc-dev-guide Cronjob Bot 2025-05-19 04:16:41 +00:00
commit 288ca05976
715 changed files with 15528 additions and 10606 deletions

View file

@ -0,0 +1,54 @@
---
name: Future Incompatibility Tracking Issue
about: A tracking issue for a future-incompatible lint
title: Tracking Issue for future-incompatibility lint XXX
labels: C-tracking-issue C-future-incompatibility T-compiler A-lints
---
<!--
Thank you for creating a future-incompatible tracking issue! 📜 These issues
are for lints that implement a future-incompatible warning.
Remember to add team labels to the tracking issue.
For something that affects the language, this would be `T-lang`, and for libs
it would be `T-libs-api`.
Also check for any `A-` labels to add.
-->
This is the **tracking issue** for the `YOUR_LINT_NAME_HERE` future-compatibility warning and other related errors. The goal of this page is describe why this change was made and how you can fix code that is affected by it. It also provides a place to ask questions or register a complaint if you feel the change should not be made. For more information on the policy around future-compatibility warnings, see our [breaking change policy guidelines][guidelines].
[guidelines]: https://rustc-dev-guide.rust-lang.org/bug-fix-procedure.html
### What is the warning for?
*Describe the conditions that trigger the warning.*
### Why was this change made?
*Explain why this change was made. If there is additional context, like an MCP, link it here.*
### Example
```rust
// Include an example here.
```
### Recommendations
*Give some recommendations on how a user can avoid the lint.*
### When will this warning become a hard error?
*If known, describe the future plans. For example, how long you anticipate this being a warning, or if there are other factors that will influence the anticipated closure.*
### Steps
- [ ] Implement the lint
- [ ] Raise lint level to deny
- [ ] Make lint report in dependencies
- [ ] Switch to a hard error
### Implementation history
<!--
Include a list of all the PRs that were involved in implementing the lint.
-->

2
.gitmodules vendored
View file

@ -45,7 +45,7 @@
shallow = true
[submodule "src/tools/enzyme"]
path = src/tools/enzyme
url = https://github.com/rust-lang/Enzyme.git
url = https://github.com/rust-lang/enzyme.git
shallow = true
[submodule "src/gcc"]
path = src/gcc

View file

@ -216,7 +216,7 @@ dependencies = [
"memchr",
"serde",
"serde_derive",
"winnow 0.7.9",
"winnow 0.7.10",
]
[[package]]
@ -487,9 +487,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.37"
version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
dependencies = [
"clap_builder",
"clap_derive",
@ -507,9 +507,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.37"
version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
dependencies = [
"anstream",
"anstyle",
@ -537,7 +537,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "clippy"
version = "0.1.88"
version = "0.1.89"
dependencies = [
"anstream",
"askama",
@ -569,7 +569,7 @@ dependencies = [
[[package]]
name = "clippy_config"
version = "0.1.88"
version = "0.1.89"
dependencies = [
"clippy_utils",
"itertools",
@ -594,7 +594,7 @@ dependencies = [
[[package]]
name = "clippy_lints"
version = "0.1.88"
version = "0.1.89"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.1",
@ -624,7 +624,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
version = "0.1.88"
version = "0.1.89"
dependencies = [
"arrayvec",
"itertools",
@ -738,7 +738,7 @@ dependencies = [
"tracing-subscriber",
"unified-diff",
"walkdir",
"windows 0.59.0",
"windows",
]
[[package]]
@ -977,9 +977,9 @@ dependencies = [
[[package]]
name = "derive_setters"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
checksum = "d9c848e86c87e5cc305313041c5677d4d95d60baa71cf95e5f6ea2554bb629ff"
dependencies = [
"darling",
"proc-macro2",
@ -1437,9 +1437,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
@ -1587,7 +1587,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.61.0",
"windows-core",
]
[[package]]
@ -1601,14 +1601,15 @@ dependencies = [
[[package]]
name = "icu_collections"
version = "1.5.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
dependencies = [
"displaydoc",
"yoke",
"potential_utf",
"yoke 0.8.0",
"zerofrom",
"zerovec",
"zerovec 0.11.2",
]
[[package]]
@ -1620,9 +1621,9 @@ dependencies = [
"displaydoc",
"icu_list_data",
"icu_locid_transform",
"icu_provider",
"icu_provider 1.5.0",
"regex-automata 0.2.0",
"writeable",
"writeable 0.5.5",
]
[[package]]
@ -1631,6 +1632,19 @@ version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52b1a7fbdbf3958f1be8354cb59ac73f165b7b7082d447ff2090355c9a069120"
[[package]]
name = "icu_locale_core"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
dependencies = [
"displaydoc",
"litemap 0.8.0",
"tinystr 0.8.1",
"writeable 0.6.1",
"zerovec 0.11.2",
]
[[package]]
name = "icu_locid"
version = "1.5.0"
@ -1638,10 +1652,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
"litemap 0.7.5",
"tinystr 0.7.6",
"writeable 0.5.5",
"zerovec 0.10.4",
]
[[package]]
@ -1653,9 +1667,9 @@ dependencies = [
"displaydoc",
"icu_locid",
"icu_locid_transform_data",
"icu_provider",
"tinystr",
"zerovec",
"icu_provider 1.5.0",
"tinystr 0.7.6",
"zerovec 0.10.4",
]
[[package]]
@ -1666,48 +1680,46 @@ checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
[[package]]
name = "icu_normalizer"
version = "1.5.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
dependencies = [
"displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"icu_provider 2.0.0",
"smallvec",
"utf16_iter",
"utf8_iter",
"write16",
"zerovec",
"zerovec 0.11.2",
]
[[package]]
name = "icu_normalizer_data"
version = "1.5.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
[[package]]
name = "icu_properties"
version = "1.5.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locid_transform",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"tinystr",
"zerovec",
"icu_provider 2.0.0",
"potential_utf",
"zerotrie",
"zerovec 0.11.2",
]
[[package]]
name = "icu_properties_data"
version = "1.5.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
[[package]]
name = "icu_provider"
@ -1719,11 +1731,28 @@ dependencies = [
"icu_locid",
"icu_provider_macros",
"stable_deref_trait",
"tinystr",
"writeable",
"yoke",
"tinystr 0.7.6",
"writeable 0.5.5",
"yoke 0.7.5",
"zerofrom",
"zerovec",
"zerovec 0.10.4",
]
[[package]]
name = "icu_provider"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
dependencies = [
"displaydoc",
"icu_locale_core",
"stable_deref_trait",
"tinystr 0.8.1",
"writeable 0.6.1",
"yoke 0.8.0",
"zerofrom",
"zerotrie",
"zerovec 0.11.2",
]
[[package]]
@ -1734,9 +1763,9 @@ checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc"
dependencies = [
"icu_locid",
"icu_locid_transform",
"icu_provider",
"tinystr",
"zerovec",
"icu_provider 1.5.0",
"tinystr 0.7.6",
"zerovec 0.10.4",
]
[[package]]
@ -1775,9 +1804,9 @@ dependencies = [
[[package]]
name = "idna_adapter"
version = "1.2.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [
"icu_normalizer",
"icu_properties",
@ -1905,9 +1934,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.12"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd"
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
dependencies = [
"jiff-static",
"log",
@ -1918,9 +1947,9 @@ dependencies = [
[[package]]
name = "jiff-static"
version = "0.2.12"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300"
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
dependencies = [
"proc-macro2",
"quote",
@ -1933,7 +1962,7 @@ version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
dependencies = [
"getrandom 0.3.2",
"getrandom 0.3.3",
"libc",
]
@ -2033,9 +2062,9 @@ dependencies = [
[[package]]
name = "libffi"
version = "4.0.0"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074"
checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838"
dependencies = [
"libc",
"libffi-sys",
@ -2043,9 +2072,9 @@ dependencies = [
[[package]]
name = "libffi-sys"
version = "3.2.0"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84"
checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3"
dependencies = [
"cc",
]
@ -2062,9 +2091,9 @@ dependencies = [
[[package]]
name = "libm"
version = "0.2.13"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
@ -2118,6 +2147,12 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
[[package]]
name = "litemap"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]]
name = "lld-wrapper"
version = "0.1.0"
@ -2279,7 +2314,7 @@ dependencies = [
"chrono-tz",
"colored",
"directories",
"getrandom 0.3.2",
"getrandom 0.3.3",
"libc",
"libffi",
"libloading",
@ -2769,6 +2804,15 @@ dependencies = [
"portable-atomic",
]
[[package]]
name = "potential_utf"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
dependencies = [
"zerovec 0.11.2",
]
[[package]]
name = "ppv-lite86"
version = "0.2.21"
@ -2919,7 +2963,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.2",
"getrandom 0.3.3",
]
[[package]]
@ -3074,9 +3118,9 @@ dependencies = [
[[package]]
name = "rustc-build-sysroot"
version = "0.5.4"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38"
checksum = "fb332121f7845c6bd016f9655cf22f03c2999df936694b624a88669a78667d98"
dependencies = [
"anyhow",
"rustc_version",
@ -3309,8 +3353,8 @@ dependencies = [
"icu_list",
"icu_locid",
"icu_locid_transform",
"icu_provider",
"zerovec",
"icu_provider 1.5.0",
"zerovec 0.10.4",
]
[[package]]
@ -3449,7 +3493,7 @@ dependencies = [
"thorin-dwp",
"tracing",
"wasm-encoder 0.219.2",
"windows 0.59.0",
"windows",
]
[[package]]
@ -3508,7 +3552,7 @@ dependencies = [
"tempfile",
"thin-vec",
"tracing",
"windows 0.59.0",
"windows",
]
[[package]]
@ -3571,7 +3615,7 @@ dependencies = [
"shlex",
"stable_mir",
"tracing",
"windows 0.59.0",
"windows",
]
[[package]]
@ -3626,7 +3670,7 @@ dependencies = [
"termcolor",
"termize",
"tracing",
"windows 0.59.0",
"windows",
]
[[package]]
@ -4371,7 +4415,7 @@ dependencies = [
"smallvec",
"termize",
"tracing",
"windows 0.59.0",
"windows",
]
[[package]]
@ -5058,7 +5102,7 @@ dependencies = [
"libc",
"objc2-core-foundation",
"objc2-io-kit",
"windows 0.61.1",
"windows",
]
[[package]]
@ -5084,12 +5128,12 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.19.1"
version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
"fastrand",
"getrandom 0.3.2",
"getrandom 0.3.3",
"once_cell",
"rustix",
"windows-sys 0.59.0",
@ -5264,7 +5308,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
dependencies = [
"displaydoc",
"zerovec",
"zerovec 0.10.4",
]
[[package]]
name = "tinystr"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
dependencies = [
"displaydoc",
"zerovec 0.11.2",
]
[[package]]
@ -5284,9 +5338,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.44.2"
version = "1.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
dependencies = [
"backtrace",
"bytes",
@ -5490,9 +5544,9 @@ dependencies = [
[[package]]
name = "unic-langid"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44"
checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05"
dependencies = [
"unic-langid-impl",
"unic-langid-macros",
@ -5500,30 +5554,30 @@ dependencies = [
[[package]]
name = "unic-langid-impl"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5"
checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658"
dependencies = [
"tinystr",
"tinystr 0.8.1",
]
[[package]]
name = "unic-langid-macros"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e"
checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25"
dependencies = [
"proc-macro-hack",
"tinystr",
"tinystr 0.8.1",
"unic-langid-impl",
"unic-langid-macros-impl",
]
[[package]]
name = "unic-langid-macros-impl"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b"
checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5"
dependencies = [
"proc-macro-hack",
"quote",
@ -5639,12 +5693,6 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf16_iter"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
[[package]]
name = "utf8-width"
version = "0.1.7"
@ -5669,7 +5717,7 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
dependencies = [
"getrandom 0.3.2",
"getrandom 0.3.3",
]
[[package]]
@ -5826,6 +5874,16 @@ dependencies = [
"wasmparser 0.229.0",
]
[[package]]
name = "wasm-encoder"
version = "0.230.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4349d0943718e6e434b51b9639e876293093dca4b96384fb136ab5bd5ce6660"
dependencies = [
"leb128fmt",
"wasmparser 0.230.0",
]
[[package]]
name = "wasm-metadata"
version = "0.229.0"
@ -5871,23 +5929,34 @@ dependencies = [
]
[[package]]
name = "wast"
version = "229.0.0"
name = "wasmparser"
version = "0.230.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63fcaff613c12225696bb163f79ca38ffb40e9300eff0ff4b8aa8b2f7eadf0d9"
checksum = "808198a69b5a0535583370a51d459baa14261dfab04800c4864ee9e1a14346ed"
dependencies = [
"bitflags",
"indexmap",
"semver",
]
[[package]]
name = "wast"
version = "230.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8edac03c5fa691551531533928443faf3dc61a44f814a235c7ec5d17b7b34f1"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width 0.2.0",
"wasm-encoder 0.229.0",
"wasm-encoder 0.230.0",
]
[[package]]
name = "wat"
version = "1.229.0"
version = "1.230.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4189bad08b70455a9e9e67dc126d2dcf91fac143a80f1046747a5dde6d4c33e0"
checksum = "0d77d62229e38db83eac32bacb5f61ebb952366ab0dae90cf2b3c07a65eea894"
dependencies = [
"wast",
]
@ -5933,16 +6002,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1"
dependencies = [
"windows-core 0.59.0",
"windows-targets 0.53.0",
]
[[package]]
name = "windows"
version = "0.61.1"
@ -5950,7 +6009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
dependencies = [
"windows-collections",
"windows-core 0.61.0",
"windows-core",
"windows-future",
"windows-link",
"windows-numerics",
@ -5973,20 +6032,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-core 0.61.0",
]
[[package]]
name = "windows-core"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
dependencies = [
"windows-implement 0.59.0",
"windows-interface",
"windows-result",
"windows-strings 0.3.1",
"windows-targets 0.53.0",
"windows-core",
]
[[package]]
@ -5995,11 +6041,11 @@ version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement 0.60.0",
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings 0.4.0",
"windows-strings",
]
[[package]]
@ -6008,21 +6054,10 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
dependencies = [
"windows-core 0.61.0",
"windows-core",
"windows-link",
]
[[package]]
name = "windows-implement"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
@ -6057,7 +6092,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core 0.61.0",
"windows-core",
"windows-link",
]
@ -6070,15 +6105,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.4.0"
@ -6311,9 +6337,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.7.9"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [
"memchr",
]
@ -6370,18 +6396,18 @@ dependencies = [
"wasmparser 0.229.0",
]
[[package]]
name = "write16"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
[[package]]
name = "writeable"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]]
name = "writeable"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
[[package]]
name = "x"
version = "0.1.1"
@ -6422,7 +6448,19 @@ checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
dependencies = [
"serde",
"stable_deref_trait",
"yoke-derive",
"yoke-derive 0.7.5",
"zerofrom",
]
[[package]]
name = "yoke"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
dependencies = [
"serde",
"stable_deref_trait",
"yoke-derive 0.8.0",
"zerofrom",
]
@ -6438,6 +6476,18 @@ dependencies = [
"synstructure",
]
[[package]]
name = "yoke-derive"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
"synstructure",
]
[[package]]
name = "zerocopy"
version = "0.8.25"
@ -6479,15 +6529,37 @@ dependencies = [
"synstructure",
]
[[package]]
name = "zerotrie"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
dependencies = [
"displaydoc",
"yoke 0.8.0",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
dependencies = [
"yoke",
"yoke 0.7.5",
"zerofrom",
"zerovec-derive",
"zerovec-derive 0.10.3",
]
[[package]]
name = "zerovec"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
dependencies = [
"yoke 0.8.0",
"zerofrom",
"zerovec-derive 0.11.1",
]
[[package]]
@ -6500,3 +6572,14 @@ dependencies = [
"quote",
"syn 2.0.101",
]
[[package]]
name = "zerovec-derive"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]

View file

@ -610,7 +610,7 @@ impl Pat {
/// Walk top-down and call `it` in each place where a pattern occurs
/// starting with the root pattern `walk` is called on. If `it` returns
/// false then we will descend no further but siblings will be processed.
pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) {
pub fn walk<'ast>(&'ast self, it: &mut impl FnMut(&'ast Pat) -> bool) {
if !it(self) {
return;
}

View file

@ -621,13 +621,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
&ocx, op, span,
) {
Ok(_) => ocx.select_all_or_error(),
Err(e) => {
if e.is_empty() {
ocx.select_all_or_error()
} else {
e
}
}
Err(e) => e,
};
// Could have no errors if a type lowering error, say, caused the query

View file

@ -18,7 +18,31 @@ use {rustc_ast as ast, rustc_parse_format as parse};
use crate::errors;
use crate::util::{ExprToSpannedString, expr_to_spanned_string};
pub struct AsmArgs {
/// An argument to one of the `asm!` macros. The argument is syntactically valid, but is otherwise
/// not validated at all.
pub struct AsmArg {
pub kind: AsmArgKind,
pub span: Span,
}
pub enum AsmArgKind {
Template(P<ast::Expr>),
Operand(Option<Symbol>, ast::InlineAsmOperand),
Options(Vec<AsmOption>),
ClobberAbi(Vec<(Symbol, Span)>),
}
pub struct AsmOption {
pub symbol: Symbol,
pub span: Span,
// A bitset, with only the bit for this option's symbol set.
pub options: ast::InlineAsmOptions,
// Used when suggesting to remove an option.
pub span_with_comma: Span,
}
/// Validated assembly arguments, ready for macro expansion.
struct ValidatedAsmArgs {
pub templates: Vec<P<ast::Expr>>,
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxIndexMap<Symbol, usize>,
@ -59,41 +83,95 @@ fn eat_operand_keyword<'a>(
}
}
fn parse_args<'a>(
ecx: &ExtCtxt<'a>,
sp: Span,
tts: TokenStream,
fn parse_asm_operand<'a>(
p: &mut Parser<'a>,
asm_macro: AsmMacro,
) -> PResult<'a, AsmArgs> {
let mut p = ecx.new_parser_from_tts(tts);
parse_asm_args(&mut p, sp, asm_macro)
) -> PResult<'a, Option<ast::InlineAsmOperand>> {
let dcx = p.dcx();
Ok(Some(if eat_operand_keyword(p, exp!(In), asm_macro)? {
let reg = parse_reg(p)?;
if p.eat_keyword(exp!(Underscore)) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
ast::InlineAsmOperand::In { reg, expr }
} else if eat_operand_keyword(p, exp!(Out), asm_macro)? {
let reg = parse_reg(p)?;
let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: false }
} else if eat_operand_keyword(p, exp!(Lateout), asm_macro)? {
let reg = parse_reg(p)?;
let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: true }
} else if eat_operand_keyword(p, exp!(Inout), asm_macro)? {
let reg = parse_reg(p)?;
if p.eat_keyword(exp!(Underscore)) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
if p.eat(exp!(FatArrow)) {
let out_expr =
if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: false }
} else {
ast::InlineAsmOperand::InOut { reg, expr, late: false }
}
} else if eat_operand_keyword(p, exp!(Inlateout), asm_macro)? {
let reg = parse_reg(p)?;
if p.eat_keyword(exp!(Underscore)) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
if p.eat(exp!(FatArrow)) {
let out_expr =
if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: true }
} else {
ast::InlineAsmOperand::InOut { reg, expr, late: true }
}
} else if eat_operand_keyword(p, exp!(Label), asm_macro)? {
let block = p.parse_block()?;
ast::InlineAsmOperand::Label { block }
} else if p.eat_keyword(exp!(Const)) {
let anon_const = p.parse_expr_anon_const()?;
ast::InlineAsmOperand::Const { anon_const }
} else if p.eat_keyword(exp!(Sym)) {
let expr = p.parse_expr()?;
let ast::ExprKind::Path(qself, path) = &expr.kind else {
let err = dcx.create_err(errors::AsmSymNoPath { span: expr.span });
return Err(err);
};
let sym =
ast::InlineAsmSym { id: ast::DUMMY_NODE_ID, qself: qself.clone(), path: path.clone() };
ast::InlineAsmOperand::Sym { sym }
} else {
return Ok(None);
}))
}
// Primarily public for rustfmt consumption.
// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
// Public for rustfmt.
pub fn parse_asm_args<'a>(
p: &mut Parser<'a>,
sp: Span,
asm_macro: AsmMacro,
) -> PResult<'a, AsmArgs> {
) -> PResult<'a, Vec<AsmArg>> {
let dcx = p.dcx();
if p.token == token::Eof {
return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp }));
}
let mut args = Vec::new();
let first_template = p.parse_expr()?;
let mut args = AsmArgs {
templates: vec![first_template],
operands: vec![],
named_args: Default::default(),
reg_args: Default::default(),
clobber_abis: Vec::new(),
options: ast::InlineAsmOptions::empty(),
options_spans: vec![],
};
args.push(AsmArg { span: first_template.span, kind: AsmArgKind::Template(first_template) });
let mut allow_templates = true;
while p.token != token::Eof {
if !p.eat(exp!(Comma)) {
if allow_templates {
@ -104,27 +182,39 @@ pub fn parse_asm_args<'a>(
return Err(p.expect(exp!(Comma)).err().unwrap());
}
}
// Accept trailing commas.
if p.token == token::Eof {
break;
} // accept trailing commas
// Parse clobber_abi
if p.eat_keyword(exp!(ClobberAbi)) {
parse_clobber_abi(p, &mut args)?;
allow_templates = false;
continue;
}
// Parse options
if p.eat_keyword(exp!(Options)) {
parse_options(p, &mut args, asm_macro)?;
allow_templates = false;
continue;
}
let span_start = p.token.span;
// Parse operand names
// Parse `clobber_abi`.
if p.eat_keyword(exp!(ClobberAbi)) {
allow_templates = false;
args.push(AsmArg {
kind: AsmArgKind::ClobberAbi(parse_clobber_abi(p)?),
span: span_start.to(p.prev_token.span),
});
continue;
}
// Parse `options`.
if p.eat_keyword(exp!(Options)) {
allow_templates = false;
args.push(AsmArg {
kind: AsmArgKind::Options(parse_options(p, asm_macro)?),
span: span_start.to(p.prev_token.span),
});
continue;
}
// Parse operand names.
let name = if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) {
let (ident, _) = p.token.ident().unwrap();
p.bump();
@ -135,69 +225,13 @@ pub fn parse_asm_args<'a>(
None
};
let mut explicit_reg = false;
let op = if eat_operand_keyword(p, exp!(In), asm_macro)? {
let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(exp!(Underscore)) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
ast::InlineAsmOperand::In { reg, expr }
} else if eat_operand_keyword(p, exp!(Out), asm_macro)? {
let reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: false }
} else if eat_operand_keyword(p, exp!(Lateout), asm_macro)? {
let reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: true }
} else if eat_operand_keyword(p, exp!(Inout), asm_macro)? {
let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(exp!(Underscore)) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
if p.eat(exp!(FatArrow)) {
let out_expr =
if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: false }
} else {
ast::InlineAsmOperand::InOut { reg, expr, late: false }
}
} else if eat_operand_keyword(p, exp!(Inlateout), asm_macro)? {
let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(exp!(Underscore)) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
if p.eat(exp!(FatArrow)) {
let out_expr =
if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: true }
} else {
ast::InlineAsmOperand::InOut { reg, expr, late: true }
}
} else if eat_operand_keyword(p, exp!(Label), asm_macro)? {
let block = p.parse_block()?;
ast::InlineAsmOperand::Label { block }
} else if p.eat_keyword(exp!(Const)) {
let anon_const = p.parse_expr_anon_const()?;
ast::InlineAsmOperand::Const { anon_const }
} else if p.eat_keyword(exp!(Sym)) {
let expr = p.parse_expr()?;
let ast::ExprKind::Path(qself, path) = &expr.kind else {
let err = dcx.create_err(errors::AsmSymNoPath { span: expr.span });
return Err(err);
};
let sym = ast::InlineAsmSym {
id: ast::DUMMY_NODE_ID,
qself: qself.clone(),
path: path.clone(),
};
ast::InlineAsmOperand::Sym { sym }
if let Some(op) = parse_asm_operand(p, asm_macro)? {
allow_templates = false;
args.push(AsmArg {
span: span_start.to(p.prev_token.span),
kind: AsmArgKind::Operand(name, op),
});
} else if allow_templates {
let template = p.parse_expr()?;
// If it can't possibly expand to a string, provide diagnostics here to include other
@ -217,55 +251,164 @@ pub fn parse_asm_args<'a>(
return Err(err);
}
}
args.templates.push(template);
continue;
args.push(AsmArg { span: template.span, kind: AsmArgKind::Template(template) });
} else {
p.unexpected_any()?
};
allow_templates = false;
let span = span_start.to(p.prev_token.span);
let slot = args.operands.len();
args.operands.push((op, span));
// Validate the order of named, positional & explicit register operands and
// clobber_abi/options. We do this at the end once we have the full span
// of the argument available.
if explicit_reg {
if name.is_some() {
dcx.emit_err(errors::AsmExplicitRegisterName { span });
}
args.reg_args.insert(slot);
} else if let Some(name) = name {
if let Some(&prev) = args.named_args.get(&name) {
dcx.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 });
continue;
}
args.named_args.insert(name, slot);
} else if !args.named_args.is_empty() || !args.reg_args.is_empty() {
let named = args.named_args.values().map(|p| args.operands[*p].1).collect();
let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect();
dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit });
}
}
if args.options.contains(ast::InlineAsmOptions::NOMEM)
&& args.options.contains(ast::InlineAsmOptions::READONLY)
Ok(args)
}
fn parse_args<'a>(
ecx: &ExtCtxt<'a>,
sp: Span,
tts: TokenStream,
asm_macro: AsmMacro,
) -> PResult<'a, ValidatedAsmArgs> {
let args = parse_asm_args(&mut ecx.new_parser_from_tts(tts), sp, asm_macro)?;
validate_asm_args(ecx, asm_macro, args)
}
fn validate_asm_args<'a>(
ecx: &ExtCtxt<'a>,
asm_macro: AsmMacro,
args: Vec<AsmArg>,
) -> PResult<'a, ValidatedAsmArgs> {
let dcx = ecx.dcx();
let mut validated = ValidatedAsmArgs {
templates: vec![],
operands: vec![],
named_args: Default::default(),
reg_args: Default::default(),
clobber_abis: Vec::new(),
options: ast::InlineAsmOptions::empty(),
options_spans: vec![],
};
let mut allow_templates = true;
for arg in args {
match arg.kind {
AsmArgKind::Template(template) => {
// The error for the first template is delayed.
if !allow_templates {
match template.kind {
ast::ExprKind::Lit(token_lit)
if matches!(
token_lit.kind,
token::LitKind::Str | token::LitKind::StrRaw(_)
) => {}
ast::ExprKind::MacCall(..) => {}
_ => {
let err = dcx.create_err(errors::AsmExpectedOther {
span: template.span,
is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
});
return Err(err);
}
}
}
validated.templates.push(template);
}
AsmArgKind::Operand(name, op) => {
allow_templates = false;
let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_)));
let span = arg.span;
let slot = validated.operands.len();
validated.operands.push((op, span));
// Validate the order of named, positional & explicit register operands and
// clobber_abi/options. We do this at the end once we have the full span
// of the argument available.
if explicit_reg {
if name.is_some() {
dcx.emit_err(errors::AsmExplicitRegisterName { span });
}
validated.reg_args.insert(slot);
} else if let Some(name) = name {
if let Some(&prev) = validated.named_args.get(&name) {
dcx.emit_err(errors::AsmDuplicateArg {
span,
name,
prev: validated.operands[prev].1,
});
continue;
}
validated.named_args.insert(name, slot);
} else if !validated.named_args.is_empty() || !validated.reg_args.is_empty() {
let named =
validated.named_args.values().map(|p| validated.operands[*p].1).collect();
let explicit =
validated.reg_args.iter().map(|p| validated.operands[p].1).collect();
dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit });
}
}
AsmArgKind::Options(new_options) => {
allow_templates = false;
for asm_option in new_options {
let AsmOption { span, symbol, span_with_comma, options } = asm_option;
if !asm_macro.is_supported_option(options) {
// Tool-only output.
dcx.emit_err(errors::AsmUnsupportedOption {
span,
symbol,
span_with_comma,
macro_name: asm_macro.macro_name(),
});
} else if validated.options.contains(options) {
// Tool-only output.
dcx.emit_err(errors::AsmOptAlreadyprovided {
span,
symbol,
span_with_comma,
});
} else {
validated.options |= asm_option.options;
}
}
validated.options_spans.push(arg.span);
}
AsmArgKind::ClobberAbi(new_abis) => {
allow_templates = false;
match &new_abis[..] {
// This should have errored above during parsing.
[] => unreachable!(),
[(abi, _span)] => validated.clobber_abis.push((*abi, arg.span)),
_ => validated.clobber_abis.extend(new_abis),
}
}
}
}
if validated.options.contains(ast::InlineAsmOptions::NOMEM)
&& validated.options.contains(ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
let spans = validated.options_spans.clone();
dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& args.options.contains(ast::InlineAsmOptions::NORETURN)
if validated.options.contains(ast::InlineAsmOptions::PURE)
&& validated.options.contains(ast::InlineAsmOptions::NORETURN)
{
let spans = args.options_spans.clone();
let spans = validated.options_spans.clone();
dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
if validated.options.contains(ast::InlineAsmOptions::PURE)
&& !validated
.options
.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
let spans = validated.options_spans.clone();
dcx.emit_err(errors::AsmPureCombine { spans });
}
@ -273,7 +416,7 @@ pub fn parse_asm_args<'a>(
let mut outputs_sp = vec![];
let mut regclass_outputs = vec![];
let mut labels_sp = vec![];
for (op, op_sp) in &args.operands {
for (op, op_sp) in &validated.operands {
match op {
ast::InlineAsmOperand::Out { reg, expr, .. }
| ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => {
@ -296,10 +439,10 @@ pub fn parse_asm_args<'a>(
_ => {}
}
}
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
if validated.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
dcx.emit_err(errors::AsmPureNoOutput { spans: validated.options_spans.clone() });
}
if args.options.contains(ast::InlineAsmOptions::NORETURN)
if validated.options.contains(ast::InlineAsmOptions::NORETURN)
&& !outputs_sp.is_empty()
&& labels_sp.is_empty()
{
@ -307,15 +450,15 @@ pub fn parse_asm_args<'a>(
// Bail out now since this is likely to confuse MIR
return Err(err);
}
if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
if validated.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
dcx.emit_err(errors::AsmMayUnwind { labels_sp });
}
if !args.clobber_abis.is_empty() {
if !validated.clobber_abis.is_empty() {
match asm_macro {
AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
spans: validated.clobber_abis.iter().map(|(_, span)| *span).collect(),
macro_name: asm_macro.macro_name(),
});
@ -326,71 +469,21 @@ pub fn parse_asm_args<'a>(
if !regclass_outputs.is_empty() {
dcx.emit_err(errors::AsmClobberNoReg {
spans: regclass_outputs,
clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
clobbers: validated.clobber_abis.iter().map(|(_, span)| *span).collect(),
});
}
}
}
}
Ok(args)
Ok(validated)
}
/// Report a duplicate option error.
///
/// This function must be called immediately after the option token is parsed.
/// Otherwise, the suggestion will be incorrect.
fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
// Tool-only output
let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
}
/// Report an invalid option error.
///
/// This function must be called immediately after the option token is parsed.
/// Otherwise, the suggestion will be incorrect.
fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) {
// Tool-only output
let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
p.dcx().emit_err(errors::AsmUnsupportedOption {
span,
symbol,
full_span,
macro_name: asm_macro.macro_name(),
});
}
/// Try to set the provided option in the provided `AsmArgs`.
/// If it is already set, report a duplicate option error.
///
/// This function must be called immediately after the option token is parsed.
/// Otherwise, the error will not point to the correct spot.
fn try_set_option<'a>(
p: &Parser<'a>,
args: &mut AsmArgs,
asm_macro: AsmMacro,
symbol: Symbol,
option: ast::InlineAsmOptions,
) {
if !asm_macro.is_supported_option(option) {
err_unsupported_option(p, asm_macro, symbol, p.prev_token.span);
} else if args.options.contains(option) {
err_duplicate_option(p, symbol, p.prev_token.span);
} else {
args.options |= option;
}
}
fn parse_options<'a>(
p: &mut Parser<'a>,
args: &mut AsmArgs,
asm_macro: AsmMacro,
) -> PResult<'a, ()> {
let span_start = p.prev_token.span;
fn parse_options<'a>(p: &mut Parser<'a>, asm_macro: AsmMacro) -> PResult<'a, Vec<AsmOption>> {
p.expect(exp!(OpenParen))?;
let mut asm_options = Vec::new();
while !p.eat(exp!(CloseParen)) {
const OPTIONS: [(ExpKeywordPair, ast::InlineAsmOptions); ast::InlineAsmOptions::COUNT] = [
(exp!(Pure), ast::InlineAsmOptions::PURE),
@ -405,38 +498,38 @@ fn parse_options<'a>(
];
'blk: {
for (exp, option) in OPTIONS {
let kw_matched = if asm_macro.is_supported_option(option) {
for (exp, options) in OPTIONS {
// Gives a more accurate list of expected next tokens.
let kw_matched = if asm_macro.is_supported_option(options) {
p.eat_keyword(exp)
} else {
p.eat_keyword_noexpect(exp.kw)
};
if kw_matched {
try_set_option(p, args, asm_macro, exp.kw, option);
let span = p.prev_token.span;
let span_with_comma =
if p.token == token::Comma { span.to(p.token.span) } else { span };
asm_options.push(AsmOption { symbol: exp.kw, span, options, span_with_comma });
break 'blk;
}
}
return p.unexpected();
return p.unexpected_any();
}
// Allow trailing commas
// Allow trailing commas.
if p.eat(exp!(CloseParen)) {
break;
}
p.expect(exp!(Comma))?;
}
let new_span = span_start.to(p.prev_token.span);
args.options_spans.push(new_span);
Ok(())
Ok(asm_options)
}
fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, ()> {
let span_start = p.prev_token.span;
fn parse_clobber_abi<'a>(p: &mut Parser<'a>) -> PResult<'a, Vec<(Symbol, Span)>> {
p.expect(exp!(OpenParen))?;
if p.eat(exp!(CloseParen)) {
@ -462,31 +555,14 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
p.expect(exp!(Comma))?;
}
let full_span = span_start.to(p.prev_token.span);
match &new_abis[..] {
// should have errored above during parsing
[] => unreachable!(),
[(abi, _span)] => args.clobber_abis.push((*abi, full_span)),
abis => {
for (abi, span) in abis {
args.clobber_abis.push((*abi, *span));
}
}
}
Ok(())
Ok(new_abis)
}
fn parse_reg<'a>(
p: &mut Parser<'a>,
explicit_reg: &mut bool,
) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
fn parse_reg<'a>(p: &mut Parser<'a>) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
p.expect(exp!(OpenParen))?;
let result = match p.token.uninterpolate().kind {
token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name),
token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => {
*explicit_reg = true;
ast::InlineAsmRegOrRegClass::Reg(symbol)
}
_ => {
@ -503,7 +579,7 @@ fn parse_reg<'a>(
fn expand_preparsed_asm(
ecx: &mut ExtCtxt<'_>,
asm_macro: AsmMacro,
args: AsmArgs,
args: ValidatedAsmArgs,
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
let mut template = vec![];
// Register operands are implicitly used since they are not allowed to be

View file

@ -910,7 +910,7 @@ pub(crate) struct AsmOptAlreadyprovided {
pub(crate) span: Span,
pub(crate) symbol: Symbol,
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
pub(crate) full_span: Span,
pub(crate) span_with_comma: Span,
}
#[derive(Diagnostic)]
@ -921,7 +921,7 @@ pub(crate) struct AsmUnsupportedOption {
pub(crate) span: Span,
pub(crate) symbol: Symbol,
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
pub(crate) full_span: Span,
pub(crate) span_with_comma: Span,
pub(crate) macro_name: &'static str,
}

View file

@ -0,0 +1 @@
Cargo.lock linguist-generated=false

View file

@ -101,9 +101,8 @@ jobs:
if: ${{ matrix.cargo_runner }}
run: |
# FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro.
# TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc.
# TODO: remove --skip test_tile_ when it's implemented.
STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_
STDARCH_TEST_SKIP_FUNCTION="xsave,xsaveopt,xsave64,xsaveopt64" STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_tile_
# Summary job for the merge queue.
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!

View file

@ -0,0 +1,101 @@
# Contributing to rustc_codegen_gcc
Welcome to the `rustc_codegen_gcc` project! This guide will help you get started as a contributor. The project aims to provide a GCC codegen backend for rustc, allowing Rust compilation on platforms unsupported by LLVM and potentially improving runtime performance through GCC's optimizations.
## Getting Started
### Setting Up Your Development Environment
For detailed setup instructions including dependencies, build steps, and initial testing, please refer to our [README](Readme.md). The README contains the most up-to-date information on:
- Required dependencies and system packages
- Repository setup and configuration
- Build process
- Basic test verification
Once you've completed the setup process outlined in the README, you can proceed with the contributor-specific information below.
## Communication Channels
- Matrix: Join our [Matrix channel](https://matrix.to/#/#rustc_codegen_gcc:matrix.org)
- IRC: Join us on [IRC](https://web.libera.chat/#rustc_codegen_gcc)
- [GitHub Issues](https://github.com/rust-lang/rustc_codegen_gcc/issues): For bug reports and feature discussions
We encourage new contributors to join our communication channels and introduce themselves. Feel free to ask questions about where to start or discuss potential contributions.
## Understanding Core Concepts
### Common Development Tasks
#### Running Specific Tests
To run specific tests, use appropriate flags such as:
- `./y.sh test --test-libcore`
- `./y.sh test --std-tests`
- `cargo test -- <name of test>`
Additionally, you can run the tests of `libgccjit`:
```bash
# libgccjit tests
cd gcc-build/gcc
make check-jit
# For a specific test:
make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-asm.cc"
```
#### Debugging Tools
The project provides several environment variables for debugging:
- `CG_GCCJIT_DUMP_GIMPLE`: Dumps the GIMPLE IR
- `CG_RUSTFLAGS`: Additional Rust flags
- `CG_GCCJIT_DUMP_MODULE`: Dumps a specific module
- `CG_GCCJIT_DUMP_TO_FILE`: Creates C-like representation
Full list of debugging options can be found in the [README](Readme.md#env-vars).
## Making Contributions
### Finding Issues to Work On
1. Look for issues labeled with [`good first issue`](https://github.com/rust-lang/rustc_codegen_gcc/issues?q=is%3Aissue%20state%3Aopen%20label%3A"good%20first%20issue") or [`help wanted`](https://github.com/rust-lang/rustc_codegen_gcc/issues?q=is%3Aissue%20state%3Aopen%20label%3A"help%20wanted")
2. Check the [progress report](https://blog.antoyo.xyz/rustc_codegen_gcc-progress-report-34#state_of_rustc_codegen_gcc) for larger initiatives
3. Consider improving documentation or investigating [failing tests](https://github.com/rust-lang/rustc_codegen_gcc/tree/master/tests) (except `failing-ui-tests12.txt`)
### Pull Request Process
1. Fork the repository and create a new branch
2. Make your changes with clear commit messages
3. Add tests for new functionality
4. Update documentation as needed
5. Submit a PR with a description of your changes
### Code Style Guidelines
- Follow Rust standard coding conventions
- Ensure your code passes `rustfmt` and `clippy`
- Add comments explaining complex logic, especially in GCC interface code
## Additional Resources
- [Rustc Dev Guide](https://rustc-dev-guide.rust-lang.org/)
- [GCC Internals Documentation](https://gcc.gnu.org/onlinedocs/gccint/)
- Project-specific documentation in the `doc/` directory:
- [Common errors](doc/errors.md)
- [Debugging](doc/debugging.md)
- [Debugging libgccjit](doc/debugging-libgccjit.md)
- [Git subtree sync](doc/subtree.md)
- [List of useful commands](doc/tips.md)
- [Send a patch to GCC](doc/sending-gcc-patch.md)
## Getting Help
If you're stuck or unsure about anything:
1. Check the existing documentation in the `doc/` directory
2. Ask in the IRC or Matrix channels
3. Open a GitHub issue for technical problems
4. Comment on the issue you're working on if you need guidance
Remember that all contributions, including documentation improvements, bug reports, and feature requests, are valuable to the project.

View file

@ -56,18 +56,18 @@ dependencies = [
[[package]]
name = "gccjit"
version = "2.5.0"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2895ddec764de7ac76fe6c056050c4801a80109c066f177a00a9cc8dee02b29b"
checksum = "ae99a89184220d967dd300139f2d2ae7d52c1a69d632b24aacc57c54625254ce"
dependencies = [
"gccjit_sys",
]
[[package]]
name = "gccjit_sys"
version = "0.6.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac133db68db8a6a8b2c51ef4b18d8ea16682d5814c4641272fe37bbbc223d5f3"
checksum = "24edb7bfe2b7b27c6d09ed23eebfcab0b359c8fe978433f902943e6f127a0f1b"
dependencies = [
"libc",
]

View file

@ -2,7 +2,7 @@
name = "rustc_codegen_gcc"
version = "0.1.0"
authors = ["Antoni Boucher <bouanto@zoho.com>"]
edition = "2018"
edition = "2024"
license = "MIT OR Apache-2.0"
[lib]
@ -22,7 +22,7 @@ master = ["gccjit/master"]
default = ["master"]
[dependencies]
gccjit = "2.5"
gccjit = "2.7"
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" }
# Local copy.

View file

@ -12,22 +12,38 @@ This is a GCC codegen for rustc, which means it can be loaded by the existing ru
The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM.
A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc.
## Getting Started
Note: **This requires a patched libgccjit in order to work.
You need to use my [fork of gcc](https://github.com/rust-lang/gcc) which already includes these patches.**
The default configuration (see below in the [Quick start](#quick-start) section) will download a `libgccjit` built in the CI that already contains these patches, so you don't need to build this fork yourself if you use the default configuration.
### Dependencies
**rustup:** Follow the instructions on the official [website](https://www.rust-lang.org/tools/install)
- rustup: follow instructions on the [official website](https://rustup.rs)
- consider to install DejaGnu which is necessary for running the libgccjit test suite. [website](https://www.gnu.org/software/dejagnu/#downloading)
- additional packages: `flex`, `libmpfr-dev`, `libgmp-dev`, `libmpc3`, `libmpc-dev`
### Quick start
**DejaGnu:** Consider to install DejaGnu which is necessary for running the libgccjit test suite. [website](https://www.gnu.org/software/dejagnu/#downloading)
1. Clone and configure the repository:
```bash
git clone https://github.com/rust-lang/rustc_codegen_gcc
cd rustc_codegen_gcc
cp config.example.toml config.toml
```
## Building
**This requires a patched libgccjit in order to work.
You need to use my [fork of gcc](https://github.com/rust-lang/gcc) which already includes these patches.**
```bash
$ cp config.example.toml config.toml
```
2. Build and test:
```bash
./y.sh prepare # downloads and patches sysroot
./y.sh build --sysroot --release
# Verify setup with a simple test
./y.sh cargo build --manifest-path tests/hello-world/Cargo.toml
# Run full test suite (expect ~100 failing UI tests)
./y.sh test --release
```
If don't need to test GCC patches you wrote in our GCC fork, then the default configuration should
be all you need. You can update the `rustc_codegen_gcc` without worrying about GCC.
@ -143,7 +159,7 @@ You can do the same manually (although we don't recommend it):
$ LIBRARY_PATH="[gcc-path value]" LD_LIBRARY_PATH="[gcc-path value]" rustc +$(cat $CG_GCCJIT_DIR/rust-toolchain | grep 'channel' | cut -d '=' -f 2 | sed 's/"//g' | sed 's/ //g') -Cpanic=abort -Zcodegen-backend=$CG_GCCJIT_DIR/target/release/librustc_codegen_gcc.so --sysroot $CG_GCCJIT_DIR/build_sysroot/sysroot my_crate.rs
```
## Env vars
## Environment variables
* _**CG_GCCJIT_DUMP_ALL_MODULES**_: Enables dumping of all compilation modules. When set to "1", a dump is created for each module during compilation and stored in `/tmp/reproducers/`.
* _**CG_GCCJIT_DUMP_MODULE**_: Enables dumping of a specific module. When set with the module name, e.g., `CG_GCCJIT_DUMP_MODULE=module_name`, a dump of that specific module is created in `/tmp/reproducers/`.

View file

@ -1,7 +1,7 @@
[package]
name = "y"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
boml = "0.3.1"

View file

@ -60,7 +60,9 @@ pub enum Command {
fn main() {
if env::var("RUST_BACKTRACE").is_err() {
env::set_var("RUST_BACKTRACE", "1");
unsafe {
env::set_var("RUST_BACKTRACE", "1");
}
}
let command = match env::args().nth(1).as_deref() {

View file

@ -10,7 +10,7 @@ use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus, Output};
#[cfg(unix)]
extern "C" {
unsafe extern "C" {
fn raise(signal: c_int) -> c_int;
}

View file

@ -1,6 +1,14 @@
#![feature(
no_core, lang_items, intrinsics, unboxed_closures, extern_types,
decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls,
no_core,
lang_items,
intrinsics,
unboxed_closures,
extern_types,
decl_macro,
rustc_attrs,
transparent_unions,
auto_traits,
freeze_impls,
thread_local
)]
#![no_core]
@ -35,13 +43,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
pub trait DispatchFromDyn<T> {}
// &T -> &U
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> 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: ?Sized + Unsize<U>, U: ?Sized> 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: ?Sized + Unsize<U>, U: ?Sized> 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<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
#[lang = "legacy_receiver"]
@ -52,8 +60,7 @@ impl<T: ?Sized> LegacyReceiver for &mut T {}
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
#[lang = "receiver"]
trait Receiver {
}
trait Receiver {}
#[lang = "copy"]
pub trait Copy {}
@ -67,10 +74,13 @@ impl Copy for u16 {}
impl Copy for u32 {}
impl Copy for u64 {}
impl Copy for usize {}
impl Copy for u128 {}
impl Copy for i8 {}
impl Copy for i16 {}
impl Copy for i32 {}
impl Copy for i64 {}
impl Copy for isize {}
impl Copy for i128 {}
impl Copy for f32 {}
impl Copy for f64 {}
impl Copy for char {}
@ -336,7 +346,6 @@ impl PartialEq for u32 {
}
}
impl PartialEq for u64 {
fn eq(&self, other: &u64) -> bool {
(*self) == (*other)
@ -523,7 +532,11 @@ fn panic_in_cleanup() -> ! {
#[track_caller]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
libc::printf(
"index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
len,
index,
);
intrinsics::abort();
}
}
@ -551,8 +564,7 @@ pub trait Deref {
fn deref(&self) -> &Self::Target;
}
pub trait Allocator {
}
pub trait Allocator {}
impl Allocator for () {}
@ -634,6 +646,8 @@ pub union MaybeUninit<T> {
}
pub mod intrinsics {
#[rustc_intrinsic]
pub const fn black_box<T>(_dummy: T) -> T;
#[rustc_intrinsic]
pub fn abort() -> !;
#[rustc_intrinsic]
@ -711,19 +725,27 @@ pub struct VaList<'a>(&'a mut VaListImpl);
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro stringify($($t:tt)*) { /* compiler built-in */ }
pub macro stringify($($t:tt)*) {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro file() { /* compiler built-in */ }
pub macro file() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro line() { /* compiler built-in */ }
pub macro line() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro cfg() { /* compiler built-in */ }
pub macro cfg() {
/* compiler built-in */
}
pub static A_STATIC: u8 = 42;

View file

@ -1 +1 @@
0ea98a1365b81f7488073512c850e8ee951a4afd
04ce66d8c918de9273bd7101638ad8724edf5e21

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2025-04-25"
channel = "nightly-2025-05-12"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -9,9 +9,9 @@ use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf;
#[cfg(feature = "master")]
use rustc_session::config;
#[cfg(feature = "master")]
use rustc_target::callconv::Conv;
use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode};
#[cfg(feature = "master")]
use rustc_target::callconv::{Conv, RiscvInterruptKind};
use crate::builder::Builder;
use crate::context::CodegenCx;
@ -240,38 +240,57 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
#[cfg(feature = "master")]
pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute<'gcc>> {
// TODO: handle the calling conventions returning None.
let attribute = match conv {
Conv::C
| Conv::Rust
| Conv::CCmseNonSecureCall
| Conv::CCmseNonSecureEntry
| Conv::RiscvInterrupt { .. } => return None,
Conv::Cold => return None,
Conv::C | Conv::Rust => return None,
Conv::CCmseNonSecureCall => {
if arch == "arm" {
FnAttribute::ArmCmseNonsecureCall
} else {
return None;
}
}
Conv::CCmseNonSecureEntry => {
if arch == "arm" {
FnAttribute::ArmCmseNonsecureEntry
} else {
return None;
}
}
Conv::Cold => FnAttribute::Cold,
// NOTE: the preserve attributes are not yet implemented in GCC:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899
Conv::PreserveMost => return None,
Conv::PreserveAll => return None,
Conv::GpuKernel => {
// TODO(antoyo): remove clippy allow attribute when this is implemented.
#[allow(clippy::if_same_then_else)]
if arch == "amdgpu" {
return None;
FnAttribute::GcnAmdGpuHsaKernel
} else if arch == "nvptx64" {
return None;
FnAttribute::NvptxKernel
} else {
panic!("Architecture {} does not support GpuKernel calling convention", arch);
}
}
Conv::AvrInterrupt => return None,
Conv::AvrNonBlockingInterrupt => return None,
Conv::ArmAapcs => return None,
Conv::Msp430Intr => return None,
Conv::X86Fastcall => return None,
Conv::X86Intr => return None,
Conv::X86Stdcall => return None,
Conv::X86ThisCall => return None,
// TODO(antoyo): check if those AVR attributes are mapped correctly.
Conv::AvrInterrupt => FnAttribute::AvrSignal,
Conv::AvrNonBlockingInterrupt => FnAttribute::AvrInterrupt,
Conv::ArmAapcs => FnAttribute::ArmPcs("aapcs"),
Conv::Msp430Intr => FnAttribute::Msp430Interrupt,
Conv::RiscvInterrupt { kind } => {
let kind = match kind {
RiscvInterruptKind::Machine => "machine",
RiscvInterruptKind::Supervisor => "supervisor",
};
FnAttribute::RiscvInterrupt(kind)
}
Conv::X86Fastcall => FnAttribute::X86FastCall,
Conv::X86Intr => FnAttribute::X86Interrupt,
Conv::X86Stdcall => FnAttribute::X86Stdcall,
Conv::X86ThisCall => FnAttribute::X86ThisCall,
// NOTE: the vectorcall calling convention is not yet implemented in GCC:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
Conv::X86VectorCall => return None,
Conv::X86_64SysV => FnAttribute::SysvAbi,
Conv::X86_64Win64 => FnAttribute::MsAbi,
Conv::X86_64SysV => FnAttribute::X86SysvAbi,
Conv::X86_64Win64 => FnAttribute::X86MsAbi,
};
Some(attribute)
}

View file

@ -6,21 +6,69 @@ use rustc_attr_parsing::InlineAttr;
use rustc_attr_parsing::InstructionSetAttr;
#[cfg(feature = "master")]
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
#[cfg(feature = "master")]
use rustc_middle::mir::TerminatorKind;
use rustc_middle::ty;
use crate::context::CodegenCx;
use crate::gcc_util::to_gcc_features;
/// Get GCC attribute for the provided inline heuristic.
/// Checks if the function `instance` is recursively inline.
/// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive.
#[cfg(feature = "master")]
fn resursively_inline<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>,
instance: ty::Instance<'tcx>,
) -> bool {
// No body, so we can't check if this is recursively inline, so we assume it is.
if !cx.tcx.is_mir_available(instance.def_id()) {
return true;
}
// `expect_local` ought to never fail: we should be checking a function within this codegen unit.
let body = cx.tcx.optimized_mir(instance.def_id());
for block in body.basic_blocks.iter() {
let Some(ref terminator) = block.terminator else { continue };
// I assume that the recursive-inline issue applies only to functions, and not to drops.
// In principle, a recursive, `#[inline(always)]` drop could(?) exist, but I don't think it does.
let TerminatorKind::Call { ref func, .. } = terminator.kind else { continue };
let Some((def, _args)) = func.const_fn_def() else { continue };
// Check if the called function is recursively inline.
if matches!(
cx.tcx.codegen_fn_attrs(def).inline,
InlineAttr::Always | InlineAttr::Force { .. }
) {
return true;
}
}
false
}
/// Get GCC attribute for the provided inline heuristic, attached to `instance`.
#[cfg(feature = "master")]
#[inline]
fn inline_attr<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>,
inline: InlineAttr,
instance: ty::Instance<'tcx>,
) -> Option<FnAttribute<'gcc>> {
match inline {
InlineAttr::Always => {
// We can't simply always return `always_inline` unconditionally.
// It is *NOT A HINT* and does not work for recursive functions.
//
// So, it can only be applied *if*:
// The current function does not call any functions marked `#[inline(always)]`.
//
// That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost.
// We *only* need to check all the terminators of a function marked with this attribute.
if resursively_inline(cx, instance) {
Some(FnAttribute::Inline)
} else {
Some(FnAttribute::AlwaysInline)
}
}
InlineAttr::Hint => Some(FnAttribute::Inline),
InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline),
InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline),
InlineAttr::Never => {
if cx.sess().target.arch != "amdgpu" {
Some(FnAttribute::NoInline)
@ -52,7 +100,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
} else {
codegen_fn_attrs.inline
};
if let Some(attr) = inline_attr(cx, inline) {
if let Some(attr) = inline_attr(cx, inline, instance) {
if let FnAttribute::AlwaysInline = attr {
func.add_attribute(FnAttribute::Inline);
}
@ -88,14 +136,8 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
let target_features = function_features
.iter()
.filter_map(|feature| {
// FIXME(antoyo): for some reasons, disabling SSE results in the following error when
// compiling Rust for Linux:
// SSE register return with SSE disabled
// TODO(antoyo): support soft-float and retpoline-external-thunk.
if feature.contains("soft-float")
|| feature.contains("retpoline-external-thunk")
|| *feature == "-sse"
{
// TODO(antoyo): support soft-float.
if feature.contains("soft-float") {
return None;
}

View file

@ -593,7 +593,7 @@ fn thin_lto(
Ok((opt_jobs, copy_jobs))
}
pub unsafe fn optimize_thin_module(
pub fn optimize_thin_module(
thin_module: ThinModule<GccCodegenBackend>,
_cgcx: &CodegenContext<GccCodegenBackend>,
) -> Result<ModuleCodegen<GccContext>, FatalError> {

View file

@ -14,7 +14,7 @@ use crate::base::add_pic_option;
use crate::errors::CopyBitcode;
use crate::{GccCodegenBackend, GccContext};
pub(crate) unsafe fn codegen(
pub(crate) fn codegen(
cgcx: &CodegenContext<GccCodegenBackend>,
dcx: DiagCtxtHandle<'_>,
module: ModuleCodegen<GccContext>,

View file

@ -568,11 +568,28 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
) {
let mut gcc_cases = vec![];
let typ = self.val_ty(value);
for (on_val, dest) in cases {
let on_val = self.const_uint_big(typ, on_val);
gcc_cases.push(self.context.new_case(on_val, on_val, dest));
// FIXME(FractalFir): This is a workaround for a libgccjit limitation.
// Currently, libgccjit can't directly create 128 bit integers.
// Since switch cases must be values, and casts are not constant, we can't use 128 bit switch cases.
// In such a case, we will simply fall back to an if-ladder.
// This *may* be slower than a native switch, but a slow working solution is better than none at all.
if typ.is_i128(self) || typ.is_u128(self) {
for (on_val, dest) in cases {
let on_val = self.const_uint_big(typ, on_val);
let is_case =
self.context.new_comparison(self.location, ComparisonOp::Equals, value, on_val);
let next_block = self.current_func().new_block("case");
self.block.end_with_conditional(self.location, is_case, dest, next_block);
self.block = next_block;
}
self.block.end_with_jump(self.location, default_block);
} else {
for (on_val, dest) in cases {
let on_val = self.const_uint_big(typ, on_val);
gcc_cases.push(self.context.new_case(on_val, on_val, dest));
}
self.block.end_with_switch(self.location, value, default_block, &gcc_cases);
}
self.block.end_with_switch(self.location, value, default_block, &gcc_cases);
}
#[cfg(feature = "master")]

View file

@ -191,13 +191,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
// TODO(antoyo): check if it's okay that no link_section is set.
let typ = self.val_ty(cv).get_aligned(align.bytes());
let global = self.declare_private_global(&name[..], typ);
global
self.declare_private_global(&name[..], typ)
}
_ => {
let typ = self.val_ty(cv).get_aligned(align.bytes());
let global = self.declare_unnamed_global(typ);
global
self.declare_unnamed_global(typ)
}
};
global.global_set_initializer_rvalue(cv);

View file

@ -289,7 +289,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
) -> Self::DILocation {
let pos = span.lo();
let DebugLoc { file, line, col } = self.lookup_debug_loc(pos);
let loc = match file.name {
match file.name {
rustc_span::FileName::Real(ref name) => match *name {
rustc_span::RealFileName::LocalPath(ref name) => {
if let Some(name) = name.to_str() {
@ -314,7 +314,6 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
},
_ => Location::null(),
};
loc
}
}
}

View file

@ -157,6 +157,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
#[allow(clippy::let_and_return)]
fn declare_raw_fn<'gcc>(
cx: &CodegenCx<'gcc, '_>,
name: &str,

File diff suppressed because it is too large Load diff

View file

@ -4,9 +4,7 @@ mod simd;
#[cfg(feature = "master")]
use std::iter;
#[cfg(feature = "master")]
use gccjit::FunctionType;
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp};
#[cfg(feature = "master")]
use rustc_abi::ExternAbi;
use rustc_abi::{BackendRepr, HasDataLayout};
@ -132,6 +130,72 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
Some(cx.context.get_builtin_function(gcc_name))
}
// TODO(antoyo): We can probably remove these and use the fallback intrinsic implementation.
fn get_simple_function<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>,
name: Symbol,
) -> Option<Function<'gcc>> {
let (return_type, parameters, func_name) = match name {
sym::minimumf32 => {
let parameters = [
cx.context.new_parameter(None, cx.float_type, "a"),
cx.context.new_parameter(None, cx.float_type, "b"),
];
(cx.float_type, parameters, "fminimumf")
}
sym::minimumf64 => {
let parameters = [
cx.context.new_parameter(None, cx.double_type, "a"),
cx.context.new_parameter(None, cx.double_type, "b"),
];
(cx.double_type, parameters, "fminimum")
}
sym::minimumf128 => {
let f128_type = cx.type_f128();
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html
let parameters = [
cx.context.new_parameter(None, f128_type, "a"),
cx.context.new_parameter(None, f128_type, "b"),
];
(f128_type, parameters, "fminimumf128")
}
sym::maximumf32 => {
let parameters = [
cx.context.new_parameter(None, cx.float_type, "a"),
cx.context.new_parameter(None, cx.float_type, "b"),
];
(cx.float_type, parameters, "fmaximumf")
}
sym::maximumf64 => {
let parameters = [
cx.context.new_parameter(None, cx.double_type, "a"),
cx.context.new_parameter(None, cx.double_type, "b"),
];
(cx.double_type, parameters, "fmaximum")
}
sym::maximumf128 => {
let f128_type = cx.type_f128();
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html
let parameters = [
cx.context.new_parameter(None, f128_type, "a"),
cx.context.new_parameter(None, f128_type, "b"),
];
(f128_type, parameters, "fmaximumf128")
}
_ => return None,
};
Some(cx.context.new_function(
None,
FunctionType::Extern,
return_type,
&parameters,
func_name,
false,
))
}
impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn codegen_intrinsic_call(
&mut self,
@ -160,6 +224,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
let simple = get_simple_intrinsic(self, name);
let simple_func = get_simple_function(self, name);
// FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved:
// https://github.com/rust-lang/rust-clippy/issues/12497
@ -167,7 +232,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
#[allow(clippy::suspicious_else_formatting)]
let value = match name {
_ if simple.is_some() => {
let func = simple.expect("simple function");
let func = simple.expect("simple intrinsic function");
self.cx.context.new_call(
self.location,
func,
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
)
}
_ if simple_func.is_some() => {
let func = simple_func.expect("simple function");
self.cx.context.new_call(
self.location,
func,

View file

@ -16,7 +16,7 @@
#![allow(internal_features)]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
#![feature(rustc_private, decl_macro, never_type, trusted_len, let_chains)]
#![feature(rustc_private, decl_macro, never_type, trusted_len)]
#![allow(broken_intra_doc_links)]
#![recursion_limit = "256"]
#![warn(rust_2018_idioms)]
@ -454,7 +454,7 @@ impl WriteBackendMethods for GccCodegenBackend {
}
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
#[no_mangle]
#[unsafe(no_mangle)]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
#[cfg(feature = "master")]
let info = {

View file

@ -10,7 +10,7 @@ tests/ui/sepcomp/sepcomp-fns-backwards.rs
tests/ui/sepcomp/sepcomp-fns.rs
tests/ui/sepcomp/sepcomp-statics.rs
tests/ui/asm/x86_64/may_unwind.rs
tests/ui/catch-unwind-bang.rs
tests/ui/panics/catch-unwind-bang.rs
tests/ui/drop/dynamic-drop-async.rs
tests/ui/cfg/cfg-panic-abort.rs
tests/ui/drop/repeat-drop.rs
@ -94,23 +94,14 @@ tests/ui/simd/intrinsic/generic-as.rs
tests/ui/backtrace/backtrace.rs
tests/ui/lifetimes/tail-expr-lock-poisoning.rs
tests/ui/runtime/rt-explody-panic-payloads.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs

View file

@ -42,7 +42,9 @@ pub fn main_inner(profile: Profile) {
.expect("failed to get absolute path of `gcc-path`")
.display()
.to_string();
env::set_var("LD_LIBRARY_PATH", gcc_path);
unsafe {
env::set_var("LD_LIBRARY_PATH", gcc_path);
}
fn rust_filter(path: &Path) -> bool {
path.is_file() && path.extension().expect("extension").to_str().expect("to_str") == "rs"
@ -67,15 +69,14 @@ pub fn main_inner(profile: Profile) {
.test_dir("tests/run")
.test_path_filter(filter)
.test_extract(|path| {
let lines = std::fs::read_to_string(path)
std::fs::read_to_string(path)
.expect("read file")
.lines()
.skip_while(|l| !l.starts_with("//"))
.take_while(|l| l.starts_with("//"))
.map(|l| &l[2..])
.collect::<Vec<_>>()
.join("\n");
lines
.join("\n")
})
.test_cmds(move |path| {
// Test command 1: Compile `x.rs` into `tempdir/x`.

View file

@ -0,0 +1,53 @@
// Compiler:
//
// Run-time:
// status: 0
#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
use mini_core::*;
#[inline(always)]
fn fib(n: u8) -> u8 {
if n == 0 {
return 1;
}
if n == 1 {
return 1;
}
fib(n - 1) + fib(n - 2)
}
#[inline(always)]
fn fib_b(n: u8) -> u8 {
if n == 0 {
return 1;
}
if n == 1 {
return 1;
}
fib_a(n - 1) + fib_a(n - 2)
}
#[inline(always)]
fn fib_a(n: u8) -> u8 {
if n == 0 {
return 1;
}
if n == 1 {
return 1;
}
fib_b(n - 1) + fib_b(n - 2)
}
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
if fib(2) != fib_a(2) {
intrinsics::abort();
}
0
}

View file

@ -0,0 +1,37 @@
// Compiler:
//
// Run-time:
// status: 0
#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
use intrinsics::black_box;
use mini_core::*;
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
// 1st. Check that small 128 bit values work.
let val = black_box(64_u128);
match val {
0 => return 1,
1 => return 2,
64 => (),
_ => return 3,
}
// 2nd check that *large* values work.
const BIG: u128 = 0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128;
let val = black_box(BIG);
match val {
0 => return 4,
1 => return 5,
// Check that we will not match on the lower u64, if the upper qword is different!
0xcafbadddecafbeef => return 6,
0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128 => (),
_ => return 7,
}
0
}

View file

@ -12,7 +12,7 @@ def run_command(command, cwd=None):
sys.exit(1)
def clone_repository(repo_name, path, repo_url, sub_paths=None):
def clone_repository(repo_name, path, repo_url, branch="master", sub_paths=None):
if os.path.exists(path):
while True:
choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path))
@ -21,7 +21,7 @@ def clone_repository(repo_name, path, repo_url, sub_paths=None):
return
elif choice.lower() == "y":
print("Updating repository...")
run_command(["git", "pull", "origin"], cwd=path)
run_command(["git", "pull", "origin", branch], cwd=path)
return
else:
print("Didn't understand answer...")
@ -209,6 +209,7 @@ def main():
"llvm-project",
llvm_path,
"https://github.com/llvm/llvm-project",
branch="main",
sub_paths=["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"],
)
clone_repository(

View file

@ -0,0 +1,7 @@
# Documentation at https://forge.rust-lang.org/triagebot/index.html
# Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust)
[issue-links]
# Prevents mentions in commits to avoid users being spammed
[no-mentions]

View file

@ -364,12 +364,7 @@ impl<'ll> CodegenCx<'ll, '_> {
if !def_id.is_local() {
let needs_dll_storage_attr = self.use_dll_storage_attrs
// If the symbol is a foreign item, then don't automatically apply DLLImport, as
// we'll rely on the #[link] attribute instead. BUT, if this is an internal symbol
// then it may be generated by the compiler in some crate, so we do need to apply
// DLLImport when linking with the MSVC linker.
&& (!self.tcx.is_foreign_item(def_id)
|| (self.sess().target.is_like_msvc && fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)))
&& !self.tcx.is_foreign_item(def_id)
// Local definitions can never be imported, so we must not apply
// the DLLImport annotation.
&& !dso_local

View file

@ -58,5 +58,5 @@ default-features = false
features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"]
[target.'cfg(windows)'.dependencies.windows]
version = "0.59.0"
version = "0.61.0"
features = ["Win32_Globalization"]

View file

@ -768,7 +768,7 @@ fn link_natively(
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-fuse-ld=lld")
{
info!("linker output: {:?}", out);
warn!("The linker driver does not support `-fuse-ld=lld`. Retrying without it.");
info!("The linker driver does not support `-fuse-ld=lld`. Retrying without it.");
for arg in cmd.take_args() {
if arg.to_string_lossy() != "-fuse-ld=lld" {
cmd.arg(arg);

View file

@ -337,12 +337,7 @@ pub(crate) trait Linker {
fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
fn no_crt_objects(&mut self);
fn no_default_libraries(&mut self);
fn export_symbols(
&mut self,
tmpdir: &Path,
crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
);
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
fn subsystem(&mut self, subsystem: &str);
fn linker_plugin_lto(&mut self);
fn add_eh_frame_header(&mut self) {}
@ -775,12 +770,7 @@ impl<'a> Linker for GccLinker<'a> {
}
}
fn export_symbols(
&mut self,
tmpdir: &Path,
crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
) {
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
// Symbol visibility in object files typically takes care of this.
if crate_type == CrateType::Executable {
let should_export_executable_symbols =
@ -809,7 +799,7 @@ impl<'a> Linker for GccLinker<'a> {
// Write a plain, newline-separated list of symbols
let res: io::Result<()> = try {
let mut f = File::create_buffered(&path)?;
for (sym, _) in symbols {
for sym in symbols {
debug!(" _{sym}");
writeln!(f, "_{sym}")?;
}
@ -824,12 +814,11 @@ impl<'a> Linker for GccLinker<'a> {
// .def file similar to MSVC one but without LIBRARY section
// because LD doesn't like when it's empty
writeln!(f, "EXPORTS")?;
for (symbol, kind) in symbols {
let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
for symbol in symbols {
debug!(" _{symbol}");
// Quote the name in case it's reserved by linker in some way
// (this accounts for names with dots in particular).
writeln!(f, " \"{symbol}\"{kind_marker}")?;
writeln!(f, " \"{symbol}\"")?;
}
};
if let Err(error) = res {
@ -842,7 +831,7 @@ impl<'a> Linker for GccLinker<'a> {
writeln!(f, "{{")?;
if !symbols.is_empty() {
writeln!(f, " global:")?;
for (sym, _) in symbols {
for sym in symbols {
debug!(" {sym};");
writeln!(f, " {sym};")?;
}
@ -1109,12 +1098,7 @@ impl<'a> Linker for MsvcLinker<'a> {
// crates. Upstream rlibs may be linked statically to this dynamic library,
// in which case they may continue to transitively be used and hence need
// their symbols exported.
fn export_symbols(
&mut self,
tmpdir: &Path,
crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
) {
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
// Symbol visibility takes care of this typically
if crate_type == CrateType::Executable {
let should_export_executable_symbols =
@ -1132,10 +1116,9 @@ impl<'a> Linker for MsvcLinker<'a> {
// straight to exports.
writeln!(f, "LIBRARY")?;
writeln!(f, "EXPORTS")?;
for (symbol, kind) in symbols {
let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
for symbol in symbols {
debug!(" _{symbol}");
writeln!(f, " {symbol}{kind_marker}")?;
writeln!(f, " {symbol}")?;
}
};
if let Err(error) = res {
@ -1276,19 +1259,14 @@ impl<'a> Linker for EmLinker<'a> {
self.cc_arg("-nodefaultlibs");
}
fn export_symbols(
&mut self,
_tmpdir: &Path,
_crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
) {
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
debug!("EXPORTED SYMBOLS:");
self.cc_arg("-s");
let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
let encoded = serde_json::to_string(
&symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
&symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
)
.unwrap();
debug!("{encoded}");
@ -1450,13 +1428,8 @@ impl<'a> Linker for WasmLd<'a> {
fn no_default_libraries(&mut self) {}
fn export_symbols(
&mut self,
_tmpdir: &Path,
_crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
) {
for (sym, _) in symbols {
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
for sym in symbols {
self.link_args(&["--export", sym]);
}
@ -1590,7 +1563,7 @@ impl<'a> Linker for L4Bender<'a> {
self.cc_arg("-nostdlib");
}
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) {
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
// ToDo, not implemented, copy from GCC
self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
}
@ -1747,17 +1720,12 @@ impl<'a> Linker for AixLinker<'a> {
fn no_default_libraries(&mut self) {}
fn export_symbols(
&mut self,
tmpdir: &Path,
_crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
) {
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
let path = tmpdir.join("list.exp");
let res: io::Result<()> = try {
let mut f = File::create_buffered(&path)?;
// FIXME: use llvm-nm to generate export list.
for (symbol, _) in symbols {
for symbol in symbols {
debug!(" _{symbol}");
writeln!(f, " {symbol}")?;
}
@ -1801,12 +1769,9 @@ fn for_each_exported_symbols_include_dep<'tcx>(
}
}
pub(crate) fn exported_symbols(
tcx: TyCtxt<'_>,
crate_type: CrateType,
) -> Vec<(String, SymbolExportKind)> {
pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
if let Some(ref exports) = tcx.sess.target.override_export_symbols {
return exports.iter().map(|name| (name.to_string(), SymbolExportKind::Text)).collect();
return exports.iter().map(ToString::to_string).collect();
}
if let CrateType::ProcMacro = crate_type {
@ -1816,10 +1781,7 @@ pub(crate) fn exported_symbols(
}
}
fn exported_symbols_for_non_proc_macro(
tcx: TyCtxt<'_>,
crate_type: CrateType,
) -> Vec<(String, SymbolExportKind)> {
fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
let mut symbols = Vec::new();
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
@ -1827,18 +1789,17 @@ fn exported_symbols_for_non_proc_macro(
// from any cdylib. The latter doesn't work anyway as we use hidden visibility for
// compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning.
if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
symbols.push((
symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
info.kind,
symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
tcx, symbol, cnum,
));
symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, info, cnum);
symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
}
});
symbols
}
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
// `exported_symbols` will be empty when !should_codegen.
if !tcx.sess.opts.output_types.should_codegen() {
return Vec::new();
@ -1848,10 +1809,7 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, Symbol
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
vec![
(proc_macro_decls_name, SymbolExportKind::Text),
(metadata_symbol_name, SymbolExportKind::Text),
]
vec![proc_macro_decls_name, metadata_symbol_name]
}
pub(crate) fn linked_symbols(
@ -1873,9 +1831,7 @@ pub(crate) fn linked_symbols(
|| info.used
{
symbols.push((
symbol_export::linking_symbol_name_for_instance_in_crate(
tcx, symbol, info.kind, cnum,
),
symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
info.kind,
));
}
@ -1950,13 +1906,7 @@ impl<'a> Linker for PtxLinker<'a> {
fn ehcont_guard(&mut self) {}
fn export_symbols(
&mut self,
_tmpdir: &Path,
_crate_type: CrateType,
_symbols: &[(String, SymbolExportKind)],
) {
}
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
fn subsystem(&mut self, _subsystem: &str) {}
@ -2025,15 +1975,10 @@ impl<'a> Linker for LlbcLinker<'a> {
fn ehcont_guard(&mut self) {}
fn export_symbols(
&mut self,
_tmpdir: &Path,
_crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
) {
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
match _crate_type {
CrateType::Cdylib => {
for (sym, _) in symbols {
for sym in symbols {
self.link_args(&["--export-symbol", sym]);
}
}
@ -2107,16 +2052,11 @@ impl<'a> Linker for BpfLinker<'a> {
fn ehcont_guard(&mut self) {}
fn export_symbols(
&mut self,
tmpdir: &Path,
_crate_type: CrateType,
symbols: &[(String, SymbolExportKind)],
) {
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
let path = tmpdir.join("symbols");
let res: io::Result<()> = try {
let mut f = File::create_buffered(&path)?;
for (sym, _) in symbols {
for sym in symbols {
writeln!(f, "{sym}")?;
}
};

View file

@ -692,7 +692,6 @@ fn calling_convention_for_symbol<'tcx>(
pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
tcx: TyCtxt<'tcx>,
symbol: ExportedSymbol<'tcx>,
export_kind: SymbolExportKind,
instantiating_crate: CrateNum,
) -> String {
let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
@ -713,9 +712,8 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
let prefix = match &target.arch[..] {
"x86" => Some('_'),
"x86_64" => None,
// Only functions are decorated for arm64ec.
"arm64ec" if export_kind == SymbolExportKind::Text => Some('#'),
// Only x86/64 and arm64ec use symbol decorations.
"arm64ec" => Some('#'),
// Only x86/64 use symbol decorations.
_ => return undecorated,
};
@ -755,10 +753,9 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>(
/// Add it to the symbols list for all kernel functions, so that it is exported in the linked
/// object.
pub(crate) fn extend_exported_symbols<'tcx>(
symbols: &mut Vec<(String, SymbolExportKind)>,
symbols: &mut Vec<String>,
tcx: TyCtxt<'tcx>,
symbol: ExportedSymbol<'tcx>,
info: SymbolExportInfo,
instantiating_crate: CrateNum,
) {
let (conv, _) = calling_convention_for_symbol(tcx, symbol);
@ -770,7 +767,7 @@ pub(crate) fn extend_exported_symbols<'tcx>(
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
// Add the symbol for the kernel descriptor (with .kd suffix)
symbols.push((format!("{undecorated}.kd"), info.kind));
symbols.push(format!("{undecorated}.kd"));
}
fn maybe_emutls_symbol_name<'tcx>(

View file

@ -12,9 +12,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
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_hir::{ItemId, Target};
use rustc_metadata::EncodedMetadata;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
@ -1038,35 +1038,21 @@ impl CrateInfo {
// by the compiler, but that's ok because all this stuff is unstable anyway.
let target = &tcx.sess.target;
if !are_upstream_rust_objects_already_included(tcx.sess) {
let add_prefix = match (target.is_like_windows, target.arch.as_ref()) {
(true, "x86") => |name: String, _: SymbolExportKind| format!("_{name}"),
(true, "arm64ec") => {
// Only functions are decorated for arm64ec.
|name: String, export_kind: SymbolExportKind| match export_kind {
SymbolExportKind::Text => format!("#{name}"),
_ => name,
}
}
_ => |name: String, _: SymbolExportKind| name,
};
let missing_weak_lang_items: FxIndexSet<(Symbol, SymbolExportKind)> = info
let missing_weak_lang_items: FxIndexSet<Symbol> = info
.used_crates
.iter()
.flat_map(|&cnum| tcx.missing_lang_items(cnum))
.filter(|l| l.is_weak())
.filter_map(|&l| {
let name = l.link_name()?;
let export_kind = match l.target() {
Target::Fn => SymbolExportKind::Text,
Target::Static => SymbolExportKind::Data,
_ => bug!(
"Don't know what the export kind is for lang item of kind {:?}",
l.target()
),
};
lang_items::required(tcx, l).then_some((name, export_kind))
lang_items::required(tcx, l).then_some(name)
})
.collect();
let prefix = match (target.is_like_windows, target.arch.as_ref()) {
(true, "x86") => "_",
(true, "arm64ec") => "#",
_ => "",
};
// This loop only adds new items to values of the hash map, so the order in which we
// iterate over the values is not important.
@ -1079,13 +1065,10 @@ impl CrateInfo {
.for_each(|(_, linked_symbols)| {
let mut symbols = missing_weak_lang_items
.iter()
.map(|(item, export_kind)| {
.map(|item| {
(
add_prefix(
mangle_internal_symbol(tcx, item.as_str()),
*export_kind,
),
*export_kind,
format!("{prefix}{}", mangle_internal_symbol(tcx, item.as_str())),
SymbolExportKind::Text,
)
})
.collect::<Vec<_>>();
@ -1100,12 +1083,12 @@ impl CrateInfo {
// errors.
linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
(
add_prefix(
format!(
"{prefix}{}",
mangle_internal_symbol(
tcx,
global_fn_name(method.name).as_str(),
),
SymbolExportKind::Text,
global_fn_name(method.name).as_str()
)
),
SymbolExportKind::Text,
)

View file

@ -218,7 +218,7 @@ pub struct CrateInfo {
pub target_cpu: String,
pub target_features: Vec<String>,
pub crate_types: Vec<CrateType>,
pub exported_symbols: UnordMap<CrateType, Vec<(String, SymbolExportKind)>>,
pub exported_symbols: UnordMap<CrateType, Vec<String>>,
pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>,
pub local_crate_name: Symbol,
pub compiler_builtins: Option<CrateNum>,

View file

@ -353,8 +353,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if caller_fn_abi.conv != callee_fn_abi.conv {
throw_ub_custom!(
fluent::const_eval_incompatible_calling_conventions,
callee_conv = format!("{:?}", callee_fn_abi.conv),
caller_conv = format!("{:?}", caller_fn_abi.conv),
callee_conv = format!("{}", callee_fn_abi.conv),
caller_conv = format!("{}", caller_fn_abi.conv),
)
}

View file

@ -38,7 +38,7 @@ features = ["nightly"] # for may_dangle
version = "0.12"
[target.'cfg(windows)'.dependencies.windows]
version = "0.59.0"
version = "0.61.0"
features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",

View file

@ -17,7 +17,7 @@ impl Drop for MaybeTempDir {
// occur.
let dir = unsafe { ManuallyDrop::take(&mut self.dir) };
if self.keep {
let _ = dir.into_path();
let _ = dir.keep();
}
}
}

View file

@ -60,7 +60,7 @@ libc = "0.2"
# tidy-alphabetical-end
[target.'cfg(windows)'.dependencies.windows]
version = "0.59.0"
version = "0.61.0"
features = [
"Win32_System_Diagnostics_Debug",
]

View file

@ -33,7 +33,7 @@ tracing = "0.1"
# tidy-alphabetical-end
[target.'cfg(windows)'.dependencies.windows]
version = "0.59.0"
version = "0.61.0"
features = [
"Win32_Foundation",
"Win32_Security",

View file

@ -82,6 +82,8 @@ declare_features! (
(accepted, attr_literals, "1.30.0", Some(34981)),
/// Allows overloading augmented assignment operations like `a += b`.
(accepted, augmented_assignments, "1.8.0", Some(28235)),
/// Allows using `avx512*` target features.
(accepted, avx512_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
/// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
(accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287)),
/// Allows bindings in the subpattern of a binding pattern.

View file

@ -318,7 +318,6 @@ declare_features! (
(unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)),
(unstable, apx_target_feature, "1.88.0", Some(139284)),
(unstable, arm_target_feature, "1.27.0", Some(44839)),
(unstable, avx512_target_feature, "1.27.0", Some(44839)),
(unstable, bpf_target_feature, "1.54.0", Some(44839)),
(unstable, csky_target_feature, "1.73.0", Some(44839)),
(unstable, ermsb_target_feature, "1.49.0", Some(44839)),

View file

@ -2744,6 +2744,8 @@ pub enum ExprKind<'hir> {
///
/// The "then" expr is always `ExprKind::Block`. If present, the "else" expr is always
/// `ExprKind::Block` (for `else`) or `ExprKind::If` (for `else if`).
/// Note that using an `Expr` instead of a `Block` for the "then" part is intentional,
/// as it simplifies the type coercion machinery.
If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>),
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
///

View file

@ -1754,17 +1754,19 @@ pub(super) fn check_coroutine_obligations(
debug!(?typeck_results.coroutine_stalled_predicates);
let mode = if tcx.next_trait_solver_globally() {
TypingMode::post_borrowck_analysis(tcx, def_id)
// This query is conceptually between HIR typeck and
// MIR borrowck. We use the opaque types defined by HIR
// and ignore region constraints.
TypingMode::borrowck(tcx, def_id)
} else {
TypingMode::analysis_in_body(tcx, def_id)
};
let infcx = tcx
.infer_ctxt()
// typeck writeback gives us predicates with their regions erased.
// As borrowck already has checked lifetimes, we do not need to do it again.
.ignoring_regions()
.build(mode);
// Typeck writeback gives us predicates with their regions erased.
// We only need to check the goals while ignoring lifetimes to give good
// error message and to avoid breaking the assumption of `mir_borrowck`
// that all obligations already hold modulo regions.
let infcx = tcx.infer_ctxt().ignoring_regions().build(mode);
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
@ -1785,6 +1787,10 @@ pub(super) fn check_coroutine_obligations(
let key = infcx.resolve_vars_if_possible(key);
sanity_check_found_hidden_type(tcx, key, hidden_type)?;
}
} else {
// We're not checking region constraints here, so we can simply drop the
// added opaque type uses in `TypingMode::Borrowck`.
let _ = infcx.take_opaque_types();
}
Ok(())

View file

@ -3,7 +3,7 @@ use std::borrow::Cow;
use std::iter;
use hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err};
use rustc_hir::def::{DefKind, Res};
@ -356,61 +356,14 @@ fn compare_method_predicate_entailment<'tcx>(
}
if !(impl_sig, trait_sig).references_error() {
// Select obligations to make progress on inference before processing
// the wf obligation below.
// FIXME(-Znext-solver): Not needed when the hack below is removed.
let errors = ocx.select_where_possible();
if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
// See #108544. Annoying, we can end up in cases where, because of winnowing,
// we pick param env candidates over a more general impl, leading to more
// stricter lifetime requirements than we would otherwise need. This can
// trigger the lint. Instead, let's only consider type outlives and
// region outlives obligations.
//
// FIXME(-Znext-solver): Try removing this hack again once the new
// solver is stable. We should just be able to register a WF pred for
// the fn sig.
let mut wf_args: smallvec::SmallVec<[_; 4]> =
unnormalized_impl_sig.inputs_and_output.iter().map(|ty| ty.into()).collect();
// Annoyingly, asking for the WF predicates of an array (with an unevaluated const (only?))
// will give back the well-formed predicate of the same array.
let mut wf_args_seen: FxHashSet<_> = wf_args.iter().copied().collect();
while let Some(term) = wf_args.pop() {
let Some(obligations) = rustc_trait_selection::traits::wf::obligations(
infcx,
param_env,
impl_m_def_id,
0,
term,
impl_m_span,
) else {
continue;
};
for obligation in obligations {
debug!(?obligation);
match obligation.predicate.kind().skip_binder() {
// We need to register Projection oblgiations too, because we may end up with
// an implied `X::Item: 'a`, which gets desugared into `X::Item = ?0`, `?0: 'a`.
// If we only register the region outlives obligation, this leads to an unconstrained var.
// See `implied_bounds_entailment_alias_var.rs` test.
ty::PredicateKind::Clause(
ty::ClauseKind::RegionOutlives(..)
| ty::ClauseKind::TypeOutlives(..)
| ty::ClauseKind::Projection(..),
) => ocx.register_obligation(obligation),
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
if wf_args_seen.insert(term) {
wf_args.push(term)
}
}
_ => {}
}
}
}
ocx.register_obligation(traits::Obligation::new(
infcx.tcx,
cause,
param_env,
ty::ClauseKind::WellFormed(
Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)).into(),
),
));
}
// Check that all obligations are satisfied by the implementation's

View file

@ -214,11 +214,9 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
let span = tcx.def_span(impl_did);
let trait_name = "DispatchFromDyn";
let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
let source = trait_ref.self_ty();
let target = {
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
trait_ref.args.type_at(1)
};
@ -339,7 +337,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
tcx,
cause.clone(),
param_env,
ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]),
ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
));
let errors = ocx.select_all_or_error();
if !errors.is_empty() {

View file

@ -194,17 +194,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
});
if tcx.features().rustc_attrs() {
tcx.sess.time("dumping_rustc_attr_data", || {
outlives::dump::inferred_outlives(tcx);
variance::dump::variances(tcx);
collect::dump::opaque_hidden_types(tcx);
collect::dump::predicates_and_item_bounds(tcx);
collect::dump::def_parents(tcx);
collect::dump::vtables(tcx);
});
}
// Make sure we evaluate all static and (non-associated) const items, even if unused.
// If any of these fail to evaluate, we do not want this crate to pass compilation.
tcx.par_hir_body_owners(|item_def_id| {
@ -228,6 +217,17 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
}
});
if tcx.features().rustc_attrs() {
tcx.sess.time("dumping_rustc_attr_data", || {
outlives::dump::inferred_outlives(tcx);
variance::dump::variances(tcx);
collect::dump::opaque_hidden_types(tcx);
collect::dump::predicates_and_item_bounds(tcx);
collect::dump::def_parents(tcx);
collect::dump::vtables(tcx);
});
}
tcx.ensure_ok().check_unused_traits(());
}

View file

@ -490,11 +490,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
&& let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From)
{
let ty = fcx.resolve_vars_if_possible(self.cast_ty);
// Erase regions to avoid panic in `prove_value` when calling
// `type_implements_trait`.
let ty = fcx.tcx.erase_regions(ty);
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let expr_ty = fcx.tcx.erase_regions(expr_ty);
if fcx
.infcx
.type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env)

View file

@ -1080,15 +1080,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Check that this is a projection from the `Future` trait.
let trait_def_id = predicate.projection_term.trait_def_id(self.tcx);
let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
if trait_def_id != future_trait {
if !self.tcx.is_lang_item(trait_def_id, LangItem::Future) {
debug!("deduce_future_output_from_projection: not a future");
return None;
}
// The `Future` trait has only one associated item, `Output`,
// so check that this is what we see.
let output_assoc_item = self.tcx.associated_item_def_ids(future_trait)[0];
let output_assoc_item = self.tcx.associated_item_def_ids(trait_def_id)[0];
if output_assoc_item != predicate.projection_term.def_id {
span_bug!(
cause_span,

View file

@ -680,6 +680,18 @@ pub(crate) enum SuggestBoxing {
hir_typeck_suggest_boxing_when_appropriate,
applicability = "machine-applicable"
)]
ExprFieldShorthand {
#[suggestion_part(code = "{ident}: Box::new(")]
start: Span,
#[suggestion_part(code = ")")]
end: Span,
ident: Ident,
},
#[note(hir_typeck_suggest_boxing_note)]
#[multipart_suggestion(
hir_typeck_suggest_boxing_when_appropriate,
applicability = "machine-applicable"
)]
Other {
#[suggestion_part(code = "Box::new(")]
start: Span,

View file

@ -585,6 +585,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
errors::SuggestBoxing::AsyncBody
}
_ if let Node::ExprField(expr_field) = self.tcx.parent_hir_node(hir_id)
&& expr_field.is_shorthand =>
{
errors::SuggestBoxing::ExprFieldShorthand {
start: span.shrink_to_lo(),
end: span.shrink_to_hi(),
ident: expr_field.ident,
}
}
_ => errors::SuggestBoxing::Other {
start: span.shrink_to_lo(),
end: span.shrink_to_hi(),
@ -2034,6 +2043,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
Some(_) if expr.span.from_expansion() => return false,
Some(ident) => format!(": {ident}{sugg}"),
None => sugg.to_string(),
};

View file

@ -105,16 +105,26 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
}
fn assign(&mut self, span: Span, nid: HirId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
// We evaluate expressions twice occasionally in diagnostics for better
// type information or because it needs type information out-of-order.
// In order to not ICE and not lead to knock-on ambiguity errors, if we
// try to re-assign a type to a local, then just take out the previous
// type and delay a bug.
if let Some(&local) = self.fcx.locals.borrow_mut().get(&nid) {
self.fcx.dcx().span_delayed_bug(span, "evaluated expression more than once");
return local;
}
match ty_opt {
None => {
// Infer the variable's type.
let var_ty = self.fcx.next_ty_var(span);
assert_eq!(self.fcx.locals.borrow_mut().insert(nid, var_ty), None);
self.fcx.locals.borrow_mut().insert(nid, var_ty);
var_ty
}
Some(typ) => {
// Take type that the user specified.
assert_eq!(self.fcx.locals.borrow_mut().insert(nid, typ), None);
self.fcx.locals.borrow_mut().insert(nid, typ);
typ
}
}

View file

@ -98,6 +98,14 @@ impl<'tcx> InferCtxt<'tcx> {
sub_region: Region<'tcx>,
cause: &ObligationCause<'tcx>,
) {
// `is_global` means the type has no params, infer, placeholder, or non-`'static`
// free regions. If the type has none of these things, then we can skip registering
// this outlives obligation since it has no components which affect lifetime
// checking in an interesting way.
if sup_type.is_global() {
return;
}
debug!(?sup_type, ?sub_region, ?cause);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
infer::RelateParamBound(

View file

@ -996,16 +996,11 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
sess.time("MIR_borrow_checking", || {
tcx.par_hir_body_owners(|def_id| {
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure_ok().check_unsafety(def_id);
if !tcx.is_typeck_child(def_id.to_def_id()) {
// Child unsafety and borrowck happens together with the parent
tcx.ensure_ok().check_unsafety(def_id);
tcx.ensure_ok().mir_borrowck(def_id)
}
});
});
sess.time("MIR_effect_checking", || {
tcx.par_hir_body_owners(|def_id| {
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
// If we need to codegen, ensure that we emit all errors from

View file

@ -362,6 +362,10 @@ lint_impl_trait_redundant_captures = all possible in-scope parameters are alread
lint_implicit_unsafe_autorefs = implicit autoref creates a reference to the dereference of a raw pointer
.note = creating a reference requires the pointer target to be valid and imposes aliasing requirements
.raw_ptr = this raw pointer has type `{$raw_ptr_ty}`
.autoref = autoref is being applied to this expression, resulting in: `{$autoref_ty}`
.overloaded_deref = references are created through calls to explicit `Deref(Mut)::deref(_mut)` implementations
.method_def = method calls to `{$method_name}` require a reference
.suggestion = try using a raw pointer method instead; or if this reference is intentional, make it explicit
lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe

View file

@ -4,7 +4,10 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDer
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::sym;
use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
use crate::lints::{
ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsMethodNote, ImplicitUnsafeAutorefsOrigin,
ImplicitUnsafeAutorefsSuggestion,
};
use crate::{LateContext, LateLintPass, LintContext};
declare_lint! {
@ -92,25 +95,37 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
&& let adjustments = peel_derefs_adjustments(&**adjustments)
// 3. An automatically inserted reference (might come from a deref).
&& let [adjustment] = adjustments
&& let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
&& let Some((borrow_mutbl, through_overloaded_deref)) = has_implicit_borrow(adjustment)
&& let ExprKind::Unary(UnOp::Deref, dereferenced) =
// 2. Any number of place projections.
peel_place_mappers(inner).kind
// 1. Deref of a raw pointer.
&& typeck.expr_ty(dereferenced).is_raw_ptr()
// PERF: 5. b. A method call annotated with `#[rustc_no_implicit_refs]`
&& match expr.kind {
ExprKind::MethodCall(..) => matches!(
cx.typeck_results().type_dependent_def_id(expr.hir_id),
Some(def_id) if cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs)
),
_ => true,
&& let method_did = match expr.kind {
// PERF: 5. b. A method call annotated with `#[rustc_no_implicit_refs]`
ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
_ => None,
}
&& method_did.map(|did| cx.tcx.has_attr(did, sym::rustc_no_implicit_autorefs)).unwrap_or(true)
{
cx.emit_span_lint(
DANGEROUS_IMPLICIT_AUTOREFS,
expr.span.source_callsite(),
ImplicitUnsafeAutorefsDiag {
raw_ptr_span: dereferenced.span,
raw_ptr_ty: typeck.expr_ty(dereferenced),
origin: if through_overloaded_deref {
ImplicitUnsafeAutorefsOrigin::OverloadedDeref
} else {
ImplicitUnsafeAutorefsOrigin::Autoref {
autoref_span: inner.span,
autoref_ty: typeck.expr_ty_adjusted(inner),
}
},
method: method_did.map(|did| ImplicitUnsafeAutorefsMethodNote {
def_span: cx.tcx.def_span(did),
method_name: cx.tcx.item_name(did),
}),
suggestion: ImplicitUnsafeAutorefsSuggestion {
mutbl: borrow_mutbl.ref_prefix_str(),
deref: if is_coming_from_deref { "*" } else { "" },
@ -146,11 +161,12 @@ fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustmen
/// Test if some adjustment has some implicit borrow.
///
/// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it.
fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<Mutability> {
/// Returns `Some((mutability, was_an_overloaded_deref))` if the argument adjustment is
/// an implicit borrow (or has an implicit borrow via an overloaded deref).
fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Mutability, bool)> {
match kind {
&Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some(mutbl),
&Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some(mutbl.into()),
&Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some((mutbl, true)),
&Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some((mutbl.into(), false)),
Adjust::NeverToAny
| Adjust::Pointer(..)
| Adjust::ReborrowPin(..)

View file

@ -59,11 +59,38 @@ pub(crate) enum ShadowedIntoIterDiagSub {
#[derive(LintDiagnostic)]
#[diag(lint_implicit_unsafe_autorefs)]
#[note]
pub(crate) struct ImplicitUnsafeAutorefsDiag {
pub(crate) struct ImplicitUnsafeAutorefsDiag<'a> {
#[label(lint_raw_ptr)]
pub raw_ptr_span: Span,
pub raw_ptr_ty: Ty<'a>,
#[subdiagnostic]
pub origin: ImplicitUnsafeAutorefsOrigin<'a>,
#[subdiagnostic]
pub method: Option<ImplicitUnsafeAutorefsMethodNote>,
#[subdiagnostic]
pub suggestion: ImplicitUnsafeAutorefsSuggestion,
}
#[derive(Subdiagnostic)]
pub(crate) enum ImplicitUnsafeAutorefsOrigin<'a> {
#[note(lint_autoref)]
Autoref {
#[primary_span]
autoref_span: Span,
autoref_ty: Ty<'a>,
},
#[note(lint_overloaded_deref)]
OverloadedDeref,
}
#[derive(Subdiagnostic)]
#[note(lint_method_def)]
pub(crate) struct ImplicitUnsafeAutorefsMethodNote {
#[primary_span]
pub def_span: Span,
pub method_name: Symbol,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
pub(crate) struct ImplicitUnsafeAutorefsSuggestion {

View file

@ -255,6 +255,7 @@ fn main() {
} else if target.contains("haiku")
|| target.contains("darwin")
|| (is_crossed && (target.contains("dragonfly") || target.contains("solaris")))
|| target.contains("cygwin")
{
println!("cargo:rustc-link-lib=z");
} else if target.contains("netbsd") {

View file

@ -267,6 +267,18 @@ fn add_query_desc_cached_impl(
) {
let Query { name, key, modifiers, .. } = &query;
// This dead code exists to instruct rust-analyzer about the link between the `rustc_queries`
// query names and the corresponding produced provider. The issue is that by nature of this
// macro producing a higher order macro that has all its token in the macro declaration we lose
// any meaningful spans, resulting in rust-analyzer being unable to make the connection between
// the query name and the corresponding providers field. The trick to fix this is to have
// `rustc_queries` emit a field access with the given name's span which allows it to succesfully
// show references / go to definition to the correspondig provider assignment which is usually
// the more interesting place.
let ra_hint = quote! {
let crate::query::Providers { #name: _, .. };
};
// Find out if we should cache the query on disk
let cache = if let Some((args, expr)) = modifiers.cache.as_ref() {
let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ });
@ -277,6 +289,7 @@ fn add_query_desc_cached_impl(
#[allow(unused_variables, unused_braces, rustc::pass_by_value)]
#[inline]
pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool {
#ra_hint
#expr
}
}
@ -286,6 +299,7 @@ fn add_query_desc_cached_impl(
#[allow(rustc::pass_by_value)]
#[inline]
pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool {
#ra_hint
false
}
}

View file

@ -22,7 +22,7 @@ impl SymbolExportLevel {
}
/// Kind of exported symbols.
#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable, Hash)]
#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)]
pub enum SymbolExportKind {
Text,
Data,

View file

@ -52,6 +52,7 @@ pub use rustc_session::lint::RegisteredTools;
use rustc_span::hygiene::MacroKind;
use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym};
pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet};
pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
#[allow(
hidden_glob_reexports,
rustc::usage_of_type_ir_inherent,
@ -120,6 +121,7 @@ use crate::ty;
use crate::ty::codec::{TyDecoder, TyEncoder};
pub use crate::ty::diagnostics::*;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::LayoutError;
use crate::ty::util::Discr;
use crate::ty::walk::TypeWalker;
@ -1184,7 +1186,7 @@ pub struct Destructor {
#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
pub struct AsyncDestructor {
/// The `DefId` of the `impl AsyncDrop`
pub impl_did: LocalDefId,
pub impl_did: DefId,
}
#[derive(Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
@ -1877,6 +1879,11 @@ impl<'tcx> TyCtxt<'tcx> {
self.def_kind(trait_def_id) == DefKind::TraitAlias
}
/// Arena-alloc of LayoutError for coroutine layout
fn layout_error(self, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> {
self.arena.alloc(err)
}
/// Returns layout of a non-async-drop coroutine. Layout might be unavailable if the
/// coroutine is tainted by errors.
///
@ -1885,12 +1892,14 @@ impl<'tcx> TyCtxt<'tcx> {
fn ordinary_coroutine_layout(
self,
def_id: DefId,
coroutine_kind_ty: Ty<'tcx>,
) -> Option<&'tcx CoroutineLayout<'tcx>> {
args: GenericArgsRef<'tcx>,
) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
let coroutine_kind_ty = args.as_coroutine().kind_ty();
let mir = self.optimized_mir(def_id);
let ty = || Ty::new_coroutine(self, def_id, args);
// Regular coroutine
if coroutine_kind_ty.is_unit() {
mir.coroutine_layout_raw()
mir.coroutine_layout_raw().ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
} else {
// If we have a `Coroutine` that comes from an coroutine-closure,
// then it may be a by-move or by-ref body.
@ -1904,6 +1913,7 @@ impl<'tcx> TyCtxt<'tcx> {
// a by-ref coroutine.
if identity_kind_ty == coroutine_kind_ty {
mir.coroutine_layout_raw()
.ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
} else {
assert_matches!(coroutine_kind_ty.to_opt_closure_kind(), Some(ClosureKind::FnOnce));
assert_matches!(
@ -1912,6 +1922,7 @@ impl<'tcx> TyCtxt<'tcx> {
);
self.optimized_mir(self.coroutine_by_move_body_def_id(def_id))
.coroutine_layout_raw()
.ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
}
}
}
@ -1923,12 +1934,15 @@ impl<'tcx> TyCtxt<'tcx> {
self,
def_id: DefId,
args: GenericArgsRef<'tcx>,
) -> Option<&'tcx CoroutineLayout<'tcx>> {
) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
let ty = || Ty::new_coroutine(self, def_id, args);
if args[0].has_placeholders() || args[0].has_non_region_param() {
return None;
return Err(self.layout_error(LayoutError::TooGeneric(ty())));
}
let instance = InstanceKind::AsyncDropGlue(def_id, Ty::new_coroutine(self, def_id, args));
self.mir_shims(instance).coroutine_layout_raw()
self.mir_shims(instance)
.coroutine_layout_raw()
.ok_or_else(|| self.layout_error(LayoutError::Unknown(ty())))
}
/// Returns layout of a coroutine. Layout might be unavailable if the
@ -1937,7 +1951,7 @@ impl<'tcx> TyCtxt<'tcx> {
self,
def_id: DefId,
args: GenericArgsRef<'tcx>,
) -> Option<&'tcx CoroutineLayout<'tcx>> {
) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> {
if self.is_async_drop_in_place_coroutine(def_id) {
// layout of `async_drop_in_place<T>::{closure}` in case,
// when T is a coroutine, contains this internal coroutine's ptr in upvars
@ -1959,12 +1973,12 @@ impl<'tcx> TyCtxt<'tcx> {
variant_source_info,
storage_conflicts: BitMatrix::new(0, 0),
};
return Some(self.arena.alloc(proxy_layout));
return Ok(self.arena.alloc(proxy_layout));
} else {
self.async_drop_coroutine_layout(def_id, args)
}
} else {
self.ordinary_coroutine_layout(def_id, args.as_coroutine().kind_ty())
self.ordinary_coroutine_layout(def_id, args)
}
}

View file

@ -1453,9 +1453,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
// contain named regions. So we erase and anonymize everything
// here to compare the types modulo regions below.
let proj = cx.tcx().erase_regions(proj);
let proj = cx.tcx().anonymize_bound_vars(proj);
let super_proj = cx.tcx().erase_regions(super_proj);
let super_proj = cx.tcx().anonymize_bound_vars(super_proj);
proj == super_proj
});

View file

@ -1260,8 +1260,7 @@ impl<'tcx> Ty<'tcx> {
return true;
};
alloc.expect_ty().ty_adt_def().is_some_and(|alloc_adt| {
let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None);
alloc_adt.did() == global_alloc
tcx.is_lang_item(alloc_adt.did(), LangItem::GlobalAlloc)
})
}
_ => false,

View file

@ -465,7 +465,7 @@ impl<'tcx> TyCtxt<'tcx> {
dtor_candidate = Some(impl_did);
}
Some(ty::AsyncDestructor { impl_did: dtor_candidate? })
Some(ty::AsyncDestructor { impl_did: dtor_candidate?.into() })
}
/// Returns the set of types that are required to be alive in

View file

@ -1148,8 +1148,9 @@ impl UnsafeOpKind {
pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
// Closures and inline consts are handled by their owner, if it has a body
assert!(!tcx.is_typeck_child(def.to_def_id()));
// Also, don't safety check custom MIR
if tcx.is_typeck_child(def.to_def_id()) || tcx.has_attr(def, sym::custom_mir) {
if tcx.has_attr(def, sym::custom_mir) {
return;
}

View file

@ -32,7 +32,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
let mut rval_ty = rvalue.ty(self.local_decls, self.tcx);
// Not erasing this causes `Free Regions` errors in validator,
// when rval is `ReStatic`.
rval_ty = self.tcx.erase_regions_ty(rval_ty);
rval_ty = self.tcx.erase_regions(rval_ty);
place_ty = self.tcx.erase_regions(place_ty);
if place_ty != rval_ty {
let temp = self

View file

@ -836,6 +836,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
#[instrument(level = "trace", skip(self), ret)]
fn simplify_rvalue(
&mut self,
lhs: &Place<'tcx>,
rvalue: &mut Rvalue<'tcx>,
location: Location,
) -> Option<VnIndex> {
@ -855,7 +856,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
Value::Repeat(op, amount)
}
Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty),
Rvalue::Aggregate(..) => return self.simplify_aggregate(rvalue, location),
Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location),
Rvalue::Ref(_, borrow_kind, ref mut place) => {
self.simplify_place_projection(place, location);
return Some(self.new_pointer(*place, AddressKind::Ref(borrow_kind)));
@ -943,6 +944,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
fn simplify_aggregate_to_copy(
&mut self,
lhs: &Place<'tcx>,
rvalue: &mut Rvalue<'tcx>,
location: Location,
fields: &[VnIndex],
@ -982,12 +984,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
// Allow introducing places with non-constant offsets, as those are still better than
// reconstructing an aggregate.
if let Some(place) = self.try_as_place(copy_from_local_value, location, true) {
if rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty {
if let Some(place) = self.try_as_place(copy_from_local_value, location, true)
&& rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty
{
// Avoid creating `*a = copy (*b)`, as they might be aliases resulting in overlapping assignments.
// FIXME: This also avoids any kind of projection, not just derefs. We can add allowed projections.
if lhs.as_local().is_some() {
self.reused_locals.insert(place.local);
*rvalue = Rvalue::Use(Operand::Copy(place));
return Some(copy_from_local_value);
}
return Some(copy_from_local_value);
}
None
@ -995,6 +1001,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
fn simplify_aggregate(
&mut self,
lhs: &Place<'tcx>,
rvalue: &mut Rvalue<'tcx>,
location: Location,
) -> Option<VnIndex> {
@ -1090,7 +1097,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
if let AggregateTy::Def(_, _) = ty
&& let Some(value) =
self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index)
self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index)
{
return Some(value);
}
@ -1765,7 +1772,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind {
self.simplify_place_projection(lhs, location);
let value = self.simplify_rvalue(rvalue, location);
let value = self.simplify_rvalue(lhs, rvalue, location);
let value = if let Some(local) = lhs.as_local()
&& self.ssa.is_ssa(local)
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark

View file

@ -752,7 +752,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
let layout = if def_id == self.caller_body.source.def_id() {
self.caller_body
.coroutine_layout_raw()
.or_else(|| self.tcx.coroutine_layout(def_id, args))
.or_else(|| self.tcx.coroutine_layout(def_id, args).ok())
} else if self.tcx.needs_coroutine_by_move_body_def_id(def_id)
&& let ty::ClosureKind::FnOnce =
args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap()
@ -762,7 +762,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// Same if this is the by-move body of a coroutine-closure.
self.caller_body.coroutine_layout_raw()
} else {
self.tcx.coroutine_layout(def_id, args)
self.tcx.coroutine_layout(def_id, args).ok()
};
let Some(layout) = layout else {

View file

@ -2,6 +2,7 @@
pub(super) mod structural_traits;
use std::cell::Cell;
use std::ops::ControlFlow;
use derive_where::derive_where;
@ -117,24 +118,24 @@ where
) -> Result<Candidate<I>, NoSolution> {
Self::fast_reject_assumption(ecx, goal, assumption)?;
ecx.probe(|candidate: &Result<Candidate<I>, NoSolution>| match candidate {
Ok(candidate) => inspect::ProbeKind::TraitCandidate {
source: candidate.source,
result: Ok(candidate.result),
},
Err(NoSolution) => inspect::ProbeKind::TraitCandidate {
source: CandidateSource::ParamEnv(ParamEnvSource::Global),
result: Err(NoSolution),
},
// Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily
// check whether the candidate is global while considering normalization.
//
// We need to write into `source` inside of `match_assumption`, but need to access it
// in `probe` even if the candidate does not apply before we get there. We handle this
// by using a `Cell` here. We only ever write into it inside of `match_assumption`.
let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global));
ecx.probe(|result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
source: source.get(),
result: *result,
})
.enter(|ecx| {
Self::match_assumption(ecx, goal, assumption)?;
let source = ecx.characterize_param_env_assumption(goal.param_env, assumption)?;
Ok(Candidate {
source,
result: ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)?,
Self::match_assumption(ecx, goal, assumption, |ecx| {
source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
})
.map(|result| Candidate { source: source.get(), result })
}
/// Try equating an assumption predicate against a goal's predicate. If it
@ -150,10 +151,8 @@ where
) -> Result<Candidate<I>, NoSolution> {
Self::fast_reject_assumption(ecx, goal, assumption)?;
ecx.probe_trait_candidate(source).enter(|ecx| {
Self::match_assumption(ecx, goal, assumption)?;
then(ecx)
})
ecx.probe_trait_candidate(source)
.enter(|ecx| Self::match_assumption(ecx, goal, assumption, then))
}
/// Try to reject the assumption based off of simple heuristics, such as [`ty::ClauseKind`]
@ -169,7 +168,8 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution>;
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
) -> QueryResult<I>;
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, D>,

View file

@ -61,13 +61,14 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
) -> QueryResult<I> {
let host_clause = assumption.as_host_effect_clause().unwrap();
let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
Ok(())
then(ecx)
}
/// Register additional assumptions for aliases corresponding to `~const` item bounds.

View file

@ -129,7 +129,40 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
) -> QueryResult<I> {
let cx = ecx.cx();
// FIXME(generic_associated_types): Addresses aggressive inference in #92917.
//
// If this type is a GAT with currently unconstrained arguments, we do not
// want to normalize it via a candidate which only applies for a specific
// instantiation. We could otherwise keep the GAT as rigid and succeed this way.
// See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs.
//
// This only avoids normalization if the GAT arguments are fully unconstrained.
// This is quite arbitrary but fixing it causes some ambiguity, see #125196.
match goal.predicate.alias.kind(cx) {
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
for arg in goal.predicate.alias.own_args(cx).iter() {
let Some(term) = arg.as_term() else {
continue;
};
let term = ecx.structurally_normalize_term(goal.param_env, term)?;
if term.is_infer() {
return ecx.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
);
}
}
}
ty::AliasTermKind::OpaqueTy
| ty::AliasTermKind::InherentTy
| ty::AliasTermKind::InherentConst
| ty::AliasTermKind::FreeTy
| ty::AliasTermKind::FreeConst
| ty::AliasTermKind::UnevaluatedConst => {}
}
let projection_pred = assumption.as_projection_clause().unwrap();
let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred);
@ -139,7 +172,6 @@ where
// Add GAT where clauses from the trait's definition
// FIXME: We don't need these, since these are the type's own WF obligations.
let cx = ecx.cx();
ecx.add_goals(
GoalSource::AliasWellFormed,
cx.own_predicates_of(goal.predicate.def_id())
@ -147,7 +179,7 @@ where
.map(|pred| goal.with(cx, pred)),
);
Ok(())
then(ecx)
}
fn consider_additional_alias_assumptions(

View file

@ -17,7 +17,7 @@ use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidates
use crate::solve::inspect::ProbeKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
NoSolution, ParamEnvSource,
NoSolution, ParamEnvSource, QueryResult,
};
impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
@ -150,13 +150,14 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
) -> QueryResult<I> {
let trait_clause = assumption.as_trait_clause().unwrap();
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
Ok(())
then(ecx)
}
fn consider_auto_trait_candidate(

View file

@ -815,7 +815,6 @@ parse_switch_ref_box_order = switch the order of `ref` and `box`
.suggestion = swap them
parse_ternary_operator = Rust has no ternary operator
.help = use an `if-else` expression instead
parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
.suggestion = use `!` to perform bitwise not
@ -963,6 +962,8 @@ parse_use_empty_block_not_semi = expected { "`{}`" }, found `;`
parse_use_eq_instead = unexpected `==`
.suggestion = try using `=` instead
parse_use_if_else = use an `if-else` expression instead
parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
parse_use_let_not_var = write `let` instead of `var` to introduce a new variable

View file

@ -436,10 +436,28 @@ pub(crate) enum IfExpressionMissingThenBlockSub {
#[derive(Diagnostic)]
#[diag(parse_ternary_operator)]
#[help]
pub(crate) struct TernaryOperator {
#[primary_span]
pub span: Span,
/// If we have a span for the condition expression, suggest the if/else
#[subdiagnostic]
pub sugg: Option<TernaryOperatorSuggestion>,
/// Otherwise, just print the suggestion message
#[help(parse_use_if_else)]
pub no_sugg: bool,
}
#[derive(Subdiagnostic, Copy, Clone)]
#[multipart_suggestion(parse_use_if_else, applicability = "maybe-incorrect", style = "verbose")]
pub(crate) struct TernaryOperatorSuggestion {
#[suggestion_part(code = "if ")]
pub before_cond: Span,
#[suggestion_part(code = "{{")]
pub question: Span,
#[suggestion_part(code = "}} else {{")]
pub colon: Span,
#[suggestion_part(code = " }}")]
pub end: Span,
}
#[derive(Subdiagnostic)]

View file

@ -41,8 +41,9 @@ use crate::errors::{
IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam,
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
UseEqInstead, WrapType,
};
use crate::parser::attr::InnerAttrPolicy;
use crate::{exp, fluent_generated as fluent};
@ -497,7 +498,7 @@ impl<'a> Parser<'a> {
// If the user is trying to write a ternary expression, recover it and
// return an Err to prevent a cascade of irrelevant diagnostics.
if self.prev_token == token::Question
&& let Err(e) = self.maybe_recover_from_ternary_operator()
&& let Err(e) = self.maybe_recover_from_ternary_operator(None)
{
return Err(e);
}
@ -1602,12 +1603,18 @@ impl<'a> Parser<'a> {
/// Rust has no ternary operator (`cond ? then : else`). Parse it and try
/// to recover from it if `then` and `else` are valid expressions. Returns
/// an err if this appears to be a ternary expression.
pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> PResult<'a, ()> {
/// If we have the span of the condition, we can provide a better error span
/// and code suggestion.
pub(super) fn maybe_recover_from_ternary_operator(
&mut self,
cond: Option<Span>,
) -> PResult<'a, ()> {
if self.prev_token != token::Question {
return PResult::Ok(());
}
let lo = self.prev_token.span.lo();
let question = self.prev_token.span;
let lo = cond.unwrap_or(question).lo();
let snapshot = self.create_snapshot_for_diagnostic();
if match self.parse_expr() {
@ -1620,11 +1627,20 @@ impl<'a> Parser<'a> {
}
} {
if self.eat_noexpect(&token::Colon) {
let colon = self.prev_token.span;
match self.parse_expr() {
Ok(_) => {
return Err(self
.dcx()
.create_err(TernaryOperator { span: self.token.span.with_lo(lo) }));
Ok(expr) => {
let sugg = cond.map(|cond| TernaryOperatorSuggestion {
before_cond: cond.shrink_to_lo(),
question,
colon,
end: expr.span.shrink_to_hi(),
});
return Err(self.dcx().create_err(TernaryOperator {
span: self.prev_token.span.with_lo(lo),
sugg,
no_sugg: sugg.is_none(),
}));
}
Err(err) => {
err.cancel();

View file

@ -879,7 +879,12 @@ impl<'a> Parser<'a> {
{
// Just check for errors and recover; do not eat semicolon yet.
let expect_result = self.expect_one_of(&[], &[exp!(Semi), exp!(CloseBrace)]);
let expect_result =
if let Err(e) = self.maybe_recover_from_ternary_operator(Some(expr.span)) {
Err(e)
} else {
self.expect_one_of(&[], &[exp!(Semi), exp!(CloseBrace)])
};
// Try to both emit a better diagnostic, and avoid further errors by replacing
// the `expr` with `ExprKind::Err`.

View file

@ -6,7 +6,6 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![allow(unused_crate_dependencies)]
#![cfg_attr(all(feature = "rustc", bootstrap), feature(let_chains))]
// tidy-alphabetical-end
pub mod constructor;

View file

@ -2493,7 +2493,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
return None;
};
let module_name = crate_module.kind.name().unwrap_or(kw::Empty);
let module_name = crate_module.kind.name().unwrap_or(kw::Crate);
let import_snippet = match import.kind {
ImportKind::Single { source, target, .. } if source != target => {
format!("{source} as {target}")

View file

@ -111,6 +111,19 @@ enum PatBoundCtx {
Or,
}
/// Tracks bindings resolved within a pattern. This serves two purposes:
///
/// - This tracks when identifiers are bound multiple times within a pattern. In a product context,
/// this is an error. In an or-pattern, this lets us reuse the same resolution for each instance.
/// See `fresh_binding` and `resolve_pattern_inner` for more information.
///
/// - The guard expression of a guard pattern may use bindings from within the guard pattern, but
/// not from elsewhere in the pattern containing it. This allows us to isolate the bindings in the
/// subpattern to construct the scope for the guard.
///
/// Each identifier must map to at most one distinct [`Res`].
type PatternBindings = SmallVec<[(PatBoundCtx, FxIndexMap<Ident, Res>); 1]>;
/// Does this the item (from the item rib scope) allow generic parameters?
#[derive(Copy, Clone, Debug)]
pub(crate) enum HasGenericParams {
@ -786,7 +799,14 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
fn visit_pat(&mut self, p: &'ast Pat) {
let prev = self.diag_metadata.current_pat;
self.diag_metadata.current_pat = Some(p);
visit::walk_pat(self, p);
if let PatKind::Guard(subpat, _) = &p.kind {
// We walk the guard expression in `resolve_pattern_inner`. Don't resolve it twice.
self.visit_pat(subpat);
} else {
visit::walk_pat(self, p);
}
self.diag_metadata.current_pat = prev;
}
fn visit_local(&mut self, local: &'ast Local) {
@ -2297,7 +2317,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
fn resolve_fn_params(
&mut self,
has_self: bool,
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone,
) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
enum Elision {
/// We have not found any candidate.
@ -2319,15 +2339,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
let mut parameter_info = Vec::new();
let mut all_candidates = Vec::new();
// Resolve and apply bindings first so diagnostics can see if they're used in types.
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
for (index, (pat, ty)) in inputs.enumerate() {
debug!(?pat, ?ty);
for (pat, _) in inputs.clone() {
debug!("resolving bindings in pat = {pat:?}");
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
if let Some(pat) = pat {
this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
}
});
}
self.apply_pattern_bindings(bindings);
for (index, (pat, ty)) in inputs.enumerate() {
debug!("resolving type for pat = {pat:?}, ty = {ty:?}");
// Record elision candidates only for this parameter.
debug_assert_matches!(self.lifetime_elision_candidates, None);
self.lifetime_elision_candidates = Some(Default::default());
@ -3615,16 +3640,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.visit_path(&delegation.path, delegation.id);
let Some(body) = &delegation.body else { return };
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
// `PatBoundCtx` is not necessary in this context
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
let span = delegation.path.segments.last().unwrap().ident.span;
this.fresh_binding(
Ident::new(kw::SelfLower, span),
delegation.id,
PatternSource::FnParam,
&mut bindings,
);
let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules());
let res = Res::Local(delegation.id);
this.innermost_rib_bindings(ValueNS).insert(ident, res);
this.visit_block(body);
});
}
@ -3635,6 +3654,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
for Param { pat, .. } in params {
this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
}
this.apply_pattern_bindings(bindings);
});
for Param { ty, .. } in params {
self.visit_ty(ty);
@ -3851,13 +3871,32 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
fn resolve_pattern_top(&mut self, pat: &'ast Pat, pat_src: PatternSource) {
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
self.resolve_pattern(pat, pat_src, &mut bindings);
self.apply_pattern_bindings(bindings);
}
/// Apply the bindings from a pattern to the innermost rib of the current scope.
fn apply_pattern_bindings(&mut self, mut pat_bindings: PatternBindings) {
let rib_bindings = self.innermost_rib_bindings(ValueNS);
let Some((_, pat_bindings)) = pat_bindings.pop() else {
bug!("tried applying nonexistent bindings from pattern");
};
if rib_bindings.is_empty() {
// Often, such as for match arms, the bindings are introduced into a new rib.
// In this case, we can move the bindings over directly.
*rib_bindings = pat_bindings;
} else {
rib_bindings.extend(pat_bindings);
}
}
/// Resolve bindings in a pattern. `apply_pattern_bindings` must be called after to introduce
/// the bindings into scope.
fn resolve_pattern(
&mut self,
pat: &'ast Pat,
pat_src: PatternSource,
bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
bindings: &mut PatternBindings,
) {
// We walk the pattern before declaring the pattern's inner bindings,
// so that we avoid resolving a literal expression to a binding defined
@ -3890,9 +3929,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
#[tracing::instrument(skip(self, bindings), level = "debug")]
fn resolve_pattern_inner(
&mut self,
pat: &Pat,
pat: &'ast Pat,
pat_src: PatternSource,
bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
bindings: &mut PatternBindings,
) {
// Visit all direct subpatterns of this pattern.
pat.walk(&mut |pat| {
@ -3950,6 +3989,31 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
// Prevent visiting `ps` as we've already done so above.
return false;
}
PatKind::Guard(ref subpat, ref guard) => {
// Add a new set of bindings to the stack to collect bindings in `subpat`.
bindings.push((PatBoundCtx::Product, Default::default()));
// Resolving `subpat` adds bindings onto the newly-pushed context. After, the
// total number of contexts on the stack should be the same as before.
let binding_ctx_stack_len = bindings.len();
self.resolve_pattern_inner(subpat, pat_src, bindings);
assert_eq!(bindings.len(), binding_ctx_stack_len);
// These bindings, but none from the surrounding pattern, are visible in the
// guard; put them in scope and resolve `guard`.
let subpat_bindings = bindings.pop().unwrap().1;
self.with_rib(ValueNS, RibKind::Normal, |this| {
*this.innermost_rib_bindings(ValueNS) = subpat_bindings.clone();
this.resolve_expr(guard, None);
});
// Propagate the subpattern's bindings upwards.
// FIXME(guard_patterns): For `if let` guards, we'll also need to get the
// bindings introduced by the guard from its rib and propagate them upwards.
// This will require checking the identifiers for overlaps with `bindings`, like
// what `fresh_binding` does (ideally sharing its logic). To keep them separate
// from `subpat_bindings`, we can introduce a fresh rib for the guard.
bindings.last_mut().unwrap().1.extend(subpat_bindings);
// Prevent visiting `subpat` as we've already done so above.
return false;
}
_ => {}
}
true
@ -3988,20 +4052,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
ident: Ident,
pat_id: NodeId,
pat_src: PatternSource,
bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
bindings: &mut PatternBindings,
) -> Res {
// Add the binding to the local ribs, if it doesn't already exist in the bindings map.
// Add the binding to the bindings map, if it doesn't already exist.
// (We must not add it if it's in the bindings map because that breaks the assumptions
// later passes make about or-patterns.)
let ident = ident.normalize_to_macro_rules();
let mut bound_iter = bindings.iter().filter(|(_, set)| set.contains(&ident));
// Already bound in a product pattern? e.g. `(a, a)` which is not allowed.
let already_bound_and = bound_iter.clone().any(|(ctx, _)| *ctx == PatBoundCtx::Product);
// Already bound in an or-pattern? e.g. `V1(a) | V2(a)`.
// This is *required* for consistency which is checked later.
let already_bound_or = bound_iter.any(|(ctx, _)| *ctx == PatBoundCtx::Or);
let already_bound_and = bindings
.iter()
.any(|(ctx, map)| *ctx == PatBoundCtx::Product && map.contains_key(&ident));
if already_bound_and {
// Overlap in a product pattern somewhere; report an error.
use ResolutionError::*;
@ -4014,19 +4075,23 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.report_error(ident.span, error(ident));
}
// Record as bound.
bindings.last_mut().unwrap().1.insert(ident);
if already_bound_or {
// Already bound in an or-pattern? e.g. `V1(a) | V2(a)`.
// This is *required* for consistency which is checked later.
let already_bound_or = bindings
.iter()
.find_map(|(ctx, map)| if *ctx == PatBoundCtx::Or { map.get(&ident) } else { None });
let res = if let Some(&res) = already_bound_or {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
self.innermost_rib_bindings(ValueNS)[&ident]
} else {
// A completely fresh binding is added to the set.
let res = Res::Local(pat_id);
self.innermost_rib_bindings(ValueNS).insert(ident, res);
res
}
} else {
// A completely fresh binding is added to the map.
Res::Local(pat_id)
};
// Record as bound.
bindings.last_mut().unwrap().1.insert(ident, res);
res
}
fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxIndexMap<Ident, Res> {

View file

@ -33,7 +33,7 @@ libc = "0.2"
# tidy-alphabetical-end
[target.'cfg(windows)'.dependencies.windows]
version = "0.59.0"
version = "0.61.0"
features = [
"Win32_Foundation",
"Win32_System_LibraryLoader",

View file

@ -78,10 +78,16 @@ fn current_dll_path() -> Result<PathBuf, String> {
if libc::dladdr(addr, &mut info) == 0 {
return Err("dladdr failed".into());
}
if info.dli_fname.is_null() {
return Err("dladdr returned null pointer".into());
}
let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
#[cfg(target_os = "cygwin")]
let fname_ptr = info.dli_fname.as_ptr();
#[cfg(not(target_os = "cygwin"))]
let fname_ptr = {
if info.dli_fname.is_null() {
return Err("dladdr returned null pointer".into());
}
info.dli_fname
};
let bytes = CStr::from_ptr(fname_ptr).to_bytes();
let os = OsStr::from_bytes(bytes);
Ok(PathBuf::from(os))
}

View file

@ -280,6 +280,8 @@ symbols! {
IoSeek,
IoWrite,
IpAddr,
Ipv4Addr,
Ipv6Addr,
IrTyKind,
Is,
Item,

View file

@ -1,3 +1,4 @@
use std::fmt::Display;
use std::str::FromStr;
use std::{fmt, iter};
@ -895,6 +896,37 @@ impl FromStr for Conv {
}
}
fn conv_to_externabi(conv: &Conv) -> ExternAbi {
match conv {
Conv::C => ExternAbi::C { unwind: false },
Conv::Rust => ExternAbi::Rust,
Conv::PreserveMost => ExternAbi::RustCold,
Conv::ArmAapcs => ExternAbi::Aapcs { unwind: false },
Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry,
Conv::Msp430Intr => ExternAbi::Msp430Interrupt,
Conv::GpuKernel => ExternAbi::GpuKernel,
Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false },
Conv::X86Intr => ExternAbi::X86Interrupt,
Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false },
Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false },
Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false },
Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false },
Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false },
Conv::AvrInterrupt => ExternAbi::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt,
Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM,
Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => ExternAbi::RiscvInterruptS,
Conv::Cold | Conv::PreserveAll => unreachable!(),
}
}
impl Display for Conv {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", conv_to_externabi(self))
}
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(target_pointer_width = "64")]
mod size_asserts {

View file

@ -5,19 +5,7 @@ use crate::spec::{BinaryFormat, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo
pub(crate) fn opts() -> TargetOptions {
// Suppress the verbose logo and authorship debugging output, which would needlessly
// clog any log files.
let pre_link_args = TargetOptions::link_args(
LinkerFlavor::Msvc(Lld::No),
&[
"/NOLOGO",
// "Symbol is marked as dllimport, but defined in an object file"
// Harmless warning that flags a potential performance improvement: marking a symbol as
// dllimport indirects usage via the `__imp_` symbol, which isn't required if the symbol
// is in the current binary. This is tripped by __rust_no_alloc_shim_is_unstable as it
// is generated by the compiler, but marked as a foreign item (hence the dllimport) in
// the standard library.
"/IGNORE:4286",
],
);
let pre_link_args = TargetOptions::link_args(LinkerFlavor::Msvc(Lld::No), &["/NOLOGO"]);
TargetOptions {
linker_flavor: LinkerFlavor::Msvc(Lld::No),

View file

@ -1,4 +1,4 @@
use crate::spec::{FramePointer, LinkerFlavor, Lld, Target, TargetMetadata, base};
use crate::spec::{FramePointer, Target, TargetMetadata, base};
pub(crate) fn target() -> Target {
let mut base = base::windows_msvc::opts();
@ -11,11 +11,6 @@ pub(crate) fn target() -> Target {
// and other services. It must point to the previous {x29, x30} pair on the stack."
base.frame_pointer = FramePointer::NonLeaf;
// MSVC emits a warning about code that may trip "Cortex-A53 MPCore processor bug #843419" (see
// https://developer.arm.com/documentation/epm048406/latest) which is sometimes emitted by LLVM.
// Since Arm64 Windows 10+ isn't supported on that processor, it's safe to disable the warning.
base.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/arm64hazardfree"]);
Target {
llvm_target: "aarch64-pc-windows-msvc".into(),
metadata: TargetMetadata {

View file

@ -416,25 +416,25 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
),
("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]),
("avx2", Stable, &["avx"]),
("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
("avx512bf16", Stable, &["avx512bw"]),
("avx512bitalg", Stable, &["avx512bw"]),
("avx512bw", Stable, &["avx512f"]),
("avx512cd", Stable, &["avx512f"]),
("avx512dq", Stable, &["avx512f"]),
("avx512f", Stable, &["avx2", "fma", "f16c"]),
("avx512fp16", Stable, &["avx512bw"]),
("avx512ifma", Stable, &["avx512f"]),
("avx512vbmi", Stable, &["avx512bw"]),
("avx512vbmi2", Stable, &["avx512bw"]),
("avx512vl", Stable, &["avx512f"]),
("avx512vnni", Stable, &["avx512f"]),
("avx512vp2intersect", Stable, &["avx512f"]),
("avx512vpopcntdq", Stable, &["avx512f"]),
("avxifma", Stable, &["avx2"]),
("avxneconvert", Stable, &["avx2"]),
("avxvnni", Stable, &["avx2"]),
("avxvnniint16", Stable, &["avx2"]),
("avxvnniint8", Stable, &["avx2"]),
("bmi1", Stable, &[]),
("bmi2", Stable, &[]),
("cmpxchg16b", Stable, &[]),
@ -442,7 +442,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("f16c", Stable, &["avx"]),
("fma", Stable, &["avx"]),
("fxsr", Stable, &[]),
("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
("gfni", Stable, &["sse2"]),
("kl", Unstable(sym::keylocker_x86), &["sse2"]),
("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
("lzcnt", Stable, &[]),
@ -469,8 +469,8 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
("ssse3", Stable, &["sse3"]),
("tbm", Unstable(sym::tbm_target_feature), &[]),
("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
("vaes", Stable, &["avx2", "aes"]),
("vpclmulqdq", Stable, &["avx", "pclmulqdq"]),
("widekl", Unstable(sym::keylocker_x86), &["kl"]),
("x87", Unstable(sym::x87_target_feature), &[]),
("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),

View file

@ -690,24 +690,26 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>(
/// used during analysis.
pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool {
debug!("impossible_predicates(predicates={:?})", predicates);
let (infcx, param_env) =
tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
let (infcx, param_env) = tcx
.infer_ctxt()
.with_next_trait_solver(true)
.build_with_typing_env(ty::TypingEnv::fully_monomorphized());
let ocx = ObligationCtxt::new(&infcx);
let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates);
for predicate in predicates {
let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate);
ocx.register_obligation(obligation);
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
return true;
}
// Leak check for any higher-ranked trait mismatches.
// We only need to do this in the old solver, since the new solver already
// leak-checks.
if !infcx.next_trait_solver() && infcx.leak_check(ty::UniverseIndex::ROOT, None).is_err() {
// Use `select_where_possible` to only return impossible for true errors,
// and not ambiguities or overflows. Since the new trait solver forces
// some currently undetected overlap between `dyn Trait: Trait` built-in
// vs user-written impls to AMBIGUOUS, this may return ambiguity even
// with no infer vars. There may also be ways to encounter ambiguity due
// to post-mono overflow.
let true_errors = ocx.select_where_possible();
if !true_errors.is_empty() {
return true;
}

View file

@ -196,11 +196,31 @@ where
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
ty
} else {
ocx.deeply_normalize(&cause, param_env, ty)?;
// Flush errors b/c `deeply_normalize` doesn't expect pending
// obligations, and we may have pending obligations from the
// branch above (from other types).
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
return Err(errors);
}
let errors = ocx.select_where_possible();
debug!("normalize errors: {ty} ~> {errors:#?}");
return Err(errors);
// When query normalization fails, we don't get back an interesting
// reason that we could use to report an error in borrowck. In order to turn
// this into a reportable error, we deeply normalize again. We don't expect
// this to succeed, so delay a bug if it does.
match ocx.deeply_normalize(&cause, param_env, ty) {
Ok(_) => {
tcx.dcx().span_delayed_bug(
span,
format!(
"query normalize succeeded of {ty}, \
but deep normalize failed",
),
);
ty
}
Err(errors) => return Err(errors),
}
};
match ty.kind() {

View file

@ -27,8 +27,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::TypeErrorToStringExt;
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
use rustc_middle::ty::{
self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
TypingMode, Upcast, elaborate,
self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, TypingMode, Upcast, elaborate,
};
use rustc_span::{Symbol, sym};
use tracing::{debug, instrument, trace};
@ -1241,7 +1241,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
self.infcx.tcx.trait_is_coinductive(data.def_id())
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true,
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
// FIXME(generic_const_exprs): GCE needs well-formedness predicates to be
// coinductive, but GCE is on the way out anyways, so this should eventually
// be replaced with `false`.
self.infcx.tcx.features().generic_const_exprs()
}
_ => false,
})
}
@ -1669,6 +1674,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Err(());
}
let drcx = DeepRejectCtxt::relate_rigid_rigid(self.infcx.tcx);
let obligation_args = obligation.predicate.skip_binder().trait_ref.args;
if !drcx.args_may_unify(obligation_args, trait_bound.skip_binder().args) {
return Err(());
}
let trait_bound = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
HigherRankedType,
@ -1760,12 +1771,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if is_match {
let generics = self.tcx().generics_of(obligation.predicate.def_id);
// FIXME(generic-associated-types): Addresses aggressive inference in #92917.
// FIXME(generic_associated_types): Addresses aggressive inference in #92917.
// If this type is a GAT, and of the GAT args resolve to something new,
// that means that we must have newly inferred something about the GAT.
// We should give up in that case.
// FIXME(generic-associated-types): This only detects one layer of inference,
// which is probably not what we actually want, but fixing it causes some ambiguity:
//
// This only detects one layer of inference, which is probably not what we actually
// want, but fixing it causes some ambiguity:
// <https://github.com/rust-lang/rust/issues/125196>.
if !generics.is_own_empty()
&& obligation.predicate.args[generics.parent_count..].iter().any(|&p| {

View file

@ -492,9 +492,7 @@ fn layout_of_uncached<'tcx>(
ty::Coroutine(def_id, args) => {
use rustc_middle::ty::layout::PrimitiveExt as _;
let Some(info) = tcx.coroutine_layout(def_id, args) else {
return Err(error(cx, LayoutError::Unknown(ty)));
};
let info = tcx.coroutine_layout(def_id, args)?;
let local_layouts = info
.field_tys

View file

@ -8,15 +8,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout};
pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
let tcx = cx.tcx();
// Type-level uninhabitedness should always imply ABI uninhabitedness.
if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) {
assert!(
layout.is_uninhabited(),
"{:?} is type-level uninhabited but not ABI-uninhabited?",
layout.ty
);
}
if layout.size.bytes() % layout.align.abi.bytes() != 0 {
bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
}
@ -29,6 +20,19 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
return;
}
// Type-level uninhabitedness should always imply ABI uninhabitedness. This can be expensive on
// big non-exhaustive types, and is [hard to
// fix](https://github.com/rust-lang/rust/issues/141006#issuecomment-2883415000) in general.
// Only doing this sanity check when debug assertions are turned on avoids the issue for the
// very specific case of #140944.
if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) {
assert!(
layout.is_uninhabited(),
"{:?} is type-level uninhabited but not ABI-uninhabited?",
layout.ty
);
}
/// Yields non-ZST fields of the type
fn non_zst_fields<'tcx, 'a>(
cx: &'a LayoutCx<'tcx>,

View file

@ -232,6 +232,9 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
}
pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool {
if lhs == rhs {
return true;
}
self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH)
}

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