Merge from rustc
This commit is contained in:
commit
288ca05976
715 changed files with 15528 additions and 10606 deletions
54
.github/ISSUE_TEMPLATE/tracking_issue_future.md
vendored
Normal file
54
.github/ISSUE_TEMPLATE/tracking_issue_future.md
vendored
Normal 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
2
.gitmodules
vendored
|
|
@ -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
|
||||
|
|
|
|||
415
Cargo.lock
415
Cargo.lock
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
1
compiler/rustc_codegen_gcc/.gitattributes
vendored
Normal file
1
compiler/rustc_codegen_gcc/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
Cargo.lock linguist-generated=false
|
||||
|
|
@ -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!
|
||||
|
|
|
|||
101
compiler/rustc_codegen_gcc/CONTRIBUTING.md
Normal file
101
compiler/rustc_codegen_gcc/CONTRIBUTING.md
Normal 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.
|
||||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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/`.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "y"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
boml = "0.3.1"
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
0ea98a1365b81f7488073512c850e8ee951a4afd
|
||||
04ce66d8c918de9273bd7101638ad8724edf5e21
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-04-25"
|
||||
channel = "nightly-2025-05-12"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
///
|
||||
/// If there’s 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
|
|
@ -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,
|
||||
¶meters,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
53
compiler/rustc_codegen_gcc/tests/run/always_inline.rs
Normal file
53
compiler/rustc_codegen_gcc/tests/run/always_inline.rs
Normal 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
|
||||
}
|
||||
37
compiler/rustc_codegen_gcc/tests/run/switchint_128bit.rs
Normal file
37
compiler/rustc_codegen_gcc/tests/run/switchint_128bit.rs
Normal 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
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
7
compiler/rustc_codegen_gcc/triagebot.toml
Normal file
7
compiler/rustc_codegen_gcc/triagebot.toml
Normal 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]
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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}")?;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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`).
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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(());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(..)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -280,6 +280,8 @@ symbols! {
|
|||
IoSeek,
|
||||
IoWrite,
|
||||
IpAddr,
|
||||
Ipv4Addr,
|
||||
Ipv6Addr,
|
||||
IrTyKind,
|
||||
Is,
|
||||
Item,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"]),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue