mirror of
https://git.proxmox.com/git/rustc
synced 2026-01-08 21:32:41 +00:00
New upstream version 1.58.1+dfsg1
This commit is contained in:
parent
c295e0f8f6
commit
3c0e092ef8
@ -3,13 +3,14 @@
|
||||
Thank you for your interest in contributing to Rust! There are many ways to contribute
|
||||
and we appreciate all of them.
|
||||
|
||||
The best way to get started is by asking for help in the [#new
|
||||
members](https://rust-lang.zulipchat.com/#narrow/stream/122652-new-members)
|
||||
Zulip stream. We have lots of docs below of how to get started on your own, but
|
||||
the Zulip stream is the best place to *ask* for help.
|
||||
|
||||
Documentation for contributing to Rust is located in the [Guide to Rustc Development](https://rustc-dev-guide.rust-lang.org/),
|
||||
commonly known as the [rustc-dev-guide]. Despite the name, this guide documents
|
||||
not just how to develop rustc (the Rust compiler), but also how to contribute to any part
|
||||
of the Rust project.
|
||||
|
||||
To get started with contributing, please read the [Contributing to Rust] chapter of the guide.
|
||||
That chapter explains how to get your development environment set up and how to get help.
|
||||
not just how to develop rustc (the Rust compiler), but also how to contribute to the standard library and rustdoc.
|
||||
|
||||
## About the [rustc-dev-guide]
|
||||
|
||||
|
||||
226
Cargo.lock
generated
226
Cargo.lock
generated
@ -265,14 +265,23 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo"
|
||||
version = "0.58.0"
|
||||
version = "0.59.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atty",
|
||||
"bytesize",
|
||||
"cargo-platform",
|
||||
"cargo-platform 0.1.2",
|
||||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
@ -374,6 +383,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-test-macro"
|
||||
version = "0.1.0"
|
||||
@ -419,18 +437,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
|
||||
dependencies = [
|
||||
"semver 0.9.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.12.0"
|
||||
@ -442,6 +448,19 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 1.0.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargotest2"
|
||||
version = "0.1.0"
|
||||
@ -555,9 +574,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.57"
|
||||
version = "0.1.58"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.12.0",
|
||||
"cargo_metadata 0.14.0",
|
||||
"clippy_lints",
|
||||
"clippy_utils",
|
||||
"compiletest_rs",
|
||||
@ -569,7 +588,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_tools_util 0.2.0",
|
||||
"semver 0.11.0",
|
||||
"semver 1.0.3",
|
||||
"serde",
|
||||
"syn",
|
||||
"tempfile",
|
||||
@ -582,6 +601,7 @@ version = "0.0.1"
|
||||
dependencies = [
|
||||
"bytecount",
|
||||
"clap",
|
||||
"indoc",
|
||||
"itertools 0.10.1",
|
||||
"opener",
|
||||
"regex",
|
||||
@ -591,9 +611,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.57"
|
||||
version = "0.1.58"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.12.0",
|
||||
"cargo_metadata 0.14.0",
|
||||
"clippy_utils",
|
||||
"if_chain",
|
||||
"itertools 0.10.1",
|
||||
@ -601,7 +621,7 @@ dependencies = [
|
||||
"quine-mc_cluskey",
|
||||
"regex-syntax",
|
||||
"rustc-semver",
|
||||
"semver 0.11.0",
|
||||
"semver 1.0.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml",
|
||||
@ -612,7 +632,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.57"
|
||||
version = "0.1.58"
|
||||
dependencies = [
|
||||
"if_chain",
|
||||
"rustc-semver",
|
||||
@ -658,9 +678,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.49"
|
||||
version = "0.1.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20b1438ef42c655665a8ab2c1c6d605a305f031d38d9be689ddfef41a20f3aa2"
|
||||
checksum = "2467ff455350a4df7d02f1ed1449d0279605a763de5d586dcf6aa7d732508bcb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
@ -690,9 +710,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiletest_rs"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca"
|
||||
checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"filetime",
|
||||
@ -868,9 +888,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "curl"
|
||||
version = "0.4.39"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaa3b8db7f3341ddef15786d250106334d4a6c4b0ae4a46cd77082777d9849b9"
|
||||
checksum = "1bc6d233563261f8db6ffb83bbaad5a73837a6e6b28868e926337ebbdece0be3"
|
||||
dependencies = [
|
||||
"curl-sys",
|
||||
"libc",
|
||||
@ -883,9 +903,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.49+curl-7.79.1"
|
||||
version = "0.4.51+curl-7.80.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0f44960aea24a786a46907b8824ebc0e66ca06bf4e4978408c7499620343483"
|
||||
checksum = "d130987e6a6a34fe0889e1083022fa48cd90e6709a84be3fb8dd95801de5af20"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -1008,9 +1028,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dlmalloc"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254"
|
||||
checksum = "a6fe28e0bf9357092740362502f5cc7955d8dc125ebda71dec72336c2e15c62e"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
@ -1069,9 +1089,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.6.2"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime 1.3.0",
|
||||
@ -1082,12 +1102,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime 1.3.0",
|
||||
"humantime 2.0.1",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
@ -1665,6 +1685,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
|
||||
dependencies = [
|
||||
"unindent",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "installer"
|
||||
version = "0.0.0"
|
||||
@ -1688,15 +1717,6 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
@ -1880,9 +1900,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
version = "0.2.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@ -2143,6 +2163,20 @@ dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "measureme"
|
||||
version = "10.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"memmap2",
|
||||
"parking_lot",
|
||||
"perf-event-open-sys",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
@ -2247,7 +2281,7 @@ dependencies = [
|
||||
"hex 0.4.2",
|
||||
"libc",
|
||||
"log",
|
||||
"measureme",
|
||||
"measureme 9.1.2",
|
||||
"rand 0.8.4",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_version 0.4.0",
|
||||
@ -2728,9 +2762,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@ -3235,7 +3269,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"measureme",
|
||||
"measureme 9.1.2",
|
||||
"memmap2",
|
||||
"parking_lot",
|
||||
"rustc-ap-rustc_graphviz",
|
||||
@ -3568,6 +3602,7 @@ dependencies = [
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_query_system",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
@ -3673,7 +3708,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"cstr",
|
||||
"libc",
|
||||
"measureme",
|
||||
"measureme 10.0.0",
|
||||
"rustc-demangle",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
@ -3766,7 +3801,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"measureme",
|
||||
"measureme 10.0.0",
|
||||
"memmap2",
|
||||
"parking_lot",
|
||||
"rustc-hash",
|
||||
@ -4005,6 +4040,7 @@ name = "rustc_lexer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"expect-test",
|
||||
"unic-emoji-char",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
@ -4102,6 +4138,7 @@ dependencies = [
|
||||
"polonius-engine",
|
||||
"rand 0.8.4",
|
||||
"rand_xoshiro 0.6.0",
|
||||
"rustc-rayon",
|
||||
"rustc-rayon-core",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
@ -4291,7 +4328,7 @@ dependencies = [
|
||||
name = "rustc_query_impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"measureme",
|
||||
"measureme 10.0.0",
|
||||
"rustc-rayon-core",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
@ -4304,7 +4341,6 @@ dependencies = [
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4347,6 +4383,7 @@ dependencies = [
|
||||
"rustc_index",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"smallvec",
|
||||
@ -4580,8 +4617,8 @@ dependencies = [
|
||||
"itertools 0.9.0",
|
||||
"minifier",
|
||||
"pulldown-cmark 0.8.0",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rustc-rayon",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -4648,19 +4685,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "1.4.37"
|
||||
version = "1.4.38"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"anyhow",
|
||||
"bytecount",
|
||||
"cargo_metadata 0.8.2",
|
||||
"cargo_metadata 0.14.0",
|
||||
"derive-new",
|
||||
"diff",
|
||||
"dirs",
|
||||
"env_logger 0.6.2",
|
||||
"env_logger 0.8.4",
|
||||
"getopts",
|
||||
"ignore",
|
||||
"itertools 0.8.2",
|
||||
"itertools 0.9.0",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"regex",
|
||||
@ -4743,23 +4780,13 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
||||
dependencies = [
|
||||
"semver-parser 0.10.2",
|
||||
"semver-parser",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -4772,12 +4799,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.10.2"
|
||||
@ -5091,9 +5112,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.65"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
|
||||
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -5490,6 +5511,47 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-property"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
|
||||
dependencies = [
|
||||
"unic-char-range",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-range"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
|
||||
|
||||
[[package]]
|
||||
name = "unic-common"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
|
||||
|
||||
[[package]]
|
||||
name = "unic-emoji-char"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
|
||||
dependencies = [
|
||||
"unic-char-property",
|
||||
"unic-char-range",
|
||||
"unic-ucd-version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-ucd-version"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
|
||||
dependencies = [
|
||||
"unic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
@ -5578,6 +5640,12 @@ dependencies = [
|
||||
"diff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
|
||||
|
||||
[[package]]
|
||||
name = "unstable-book-gen"
|
||||
version = "0.1.0"
|
||||
|
||||
@ -77,6 +77,13 @@ overflow-checks = false
|
||||
# per-crate configuration isn't specifiable in the environment.
|
||||
codegen-units = 10000
|
||||
|
||||
[profile.release.package.rustc-rayon-core]
|
||||
# The rustc fork of Rayon has deadlock detection code which intermittently
|
||||
# causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227)
|
||||
# so we turn overflow checks off for now.
|
||||
# FIXME: This workaround should be removed once #90227 is fixed.
|
||||
overflow-checks = false
|
||||
|
||||
# These dependencies of the standard library implement symbolication for
|
||||
# backtraces on most platforms. Their debuginfo causes both linking to be slower
|
||||
# (more data to chew through) and binaries to be larger without really all that
|
||||
|
||||
@ -7,7 +7,10 @@ standard library, and documentation.
|
||||
|
||||
**Note: this README is for _users_ rather than _contributors_.
|
||||
If you wish to _contribute_ to the compiler, you should read the
|
||||
[Getting Started][gettingstarted] section of the rustc-dev-guide instead.**
|
||||
[Getting Started][gettingstarted] section of the rustc-dev-guide instead.
|
||||
You can ask for help in the [#new members Zulip stream][new-members].**
|
||||
|
||||
[new-members]: https://rust-lang.zulipchat.com/#narrow/stream/122652-new-members
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
||||
191
RELEASES.md
191
RELEASES.md
@ -1,3 +1,190 @@
|
||||
Version 1.58.1 (2022-01-19)
|
||||
===========================
|
||||
|
||||
* Fix race condition in `std::fs::remove_dir_all` ([CVE-2022-21658])
|
||||
* [Handle captured arguments in the `useless_format` Clippy lint][clippy/8295]
|
||||
* [Move `non_send_fields_in_send_ty` Clippy lint to nursery][clippy/8075]
|
||||
* [Fix wrong error message displayed when some imports are missing][91254]
|
||||
* [Fix rustfmt not formatting generated files from stdin][92912]
|
||||
|
||||
[CVE-2022-21658]: https://www.cve.org/CVERecord?id=CVE-2022-21658]
|
||||
[91254]: https://github.com/rust-lang/rust/pull/91254
|
||||
[92912]: https://github.com/rust-lang/rust/pull/92912
|
||||
[clippy/8075]: https://github.com/rust-lang/rust-clippy/pull/8075
|
||||
[clippy/8295]: https://github.com/rust-lang/rust-clippy/pull/8295
|
||||
|
||||
Version 1.58.0 (2022-01-13)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
|
||||
- [Format strings can now capture arguments simply by writing `{ident}` in the string.][90473] This works in all macros accepting format strings. Support for this in `panic!` (`panic!("{ident}")`) requires the 2021 edition; panic invocations in previous editions that appear to be trying to use this will result in a warning lint about not having the intended effect.
|
||||
- [`*const T` pointers can now be dereferenced in const contexts.][89551]
|
||||
- [The rules for when a generic struct implements `Unsize` have been relaxed.][90417]
|
||||
|
||||
Compiler
|
||||
--------
|
||||
|
||||
- [Add LLVM CFI support to the Rust compiler][89652]
|
||||
- [Stabilize -Z strip as -C strip][90058]. Note that while release builds already don't add debug symbols for the code you compile, the compiled standard library that ships with Rust includes debug symbols, so you may want to use the `strip` option to remove these symbols to produce smaller release binaries. Note that this release only includes support in rustc, not directly in cargo.
|
||||
- [Add support for LLVM coverage mapping format versions 5 and 6][91207]
|
||||
- [Emit LLVM optimization remarks when enabled with `-Cremark`][90833]
|
||||
- [Update the minimum external LLVM to 12][90175]
|
||||
- [Add `x86_64-unknown-none` at Tier 3*][89062]
|
||||
- [Build musl dist artifacts with debuginfo enabled][90733]. When building release binaries using musl, you may want to use the newly stabilized strip option to remove these debug symbols, reducing the size of your binaries.
|
||||
- [Don't abort compilation after giving a lint error][87337]
|
||||
- [Error messages point at the source of trait bound obligations in more places][89580]
|
||||
|
||||
\* Refer to Rust's [platform support page][platform-support-doc] for more
|
||||
information on Rust's tiered platform support.
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [All remaining functions in the standard library have `#[must_use]` annotations where appropriate][89692], producing a warning when ignoring their return value. This helps catch mistakes such as expecting a function to mutate a value in place rather than return a new value.
|
||||
- [Paths are automatically canonicalized on Windows for operations that support it][89174]
|
||||
- [Re-enable debug checks for `copy` and `copy_nonoverlapping`][90041]
|
||||
- [Implement `RefUnwindSafe` for `Rc<T>`][87467]
|
||||
- [Make RSplit<T, P>: Clone not require T: Clone][90117]
|
||||
- [Implement `Termination` for `Result<Infallible, E>`][88601]. This allows writing `fn main() -> Result<Infallible, ErrorType>`, for a program whose successful exits never involve returning from `main` (for instance, a program that calls `exit`, or that uses `exec` to run another program).
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`Metadata::is_symlink`]
|
||||
- [`Path::is_symlink`]
|
||||
- [`{integer}::saturating_div`]
|
||||
- [`Option::unwrap_unchecked`]
|
||||
- [`Result::unwrap_unchecked`]
|
||||
- [`Result::unwrap_err_unchecked`]
|
||||
- [`NonZero{unsigned}::is_power_of_two`]
|
||||
- [`File::options`]
|
||||
|
||||
These APIs are now usable in const contexts:
|
||||
|
||||
- [`Duration::new`]
|
||||
- [`Duration::checked_add`]
|
||||
- [`Duration::saturating_add`]
|
||||
- [`Duration::checked_sub`]
|
||||
- [`Duration::saturating_sub`]
|
||||
- [`Duration::checked_mul`]
|
||||
- [`Duration::saturating_mul`]
|
||||
- [`Duration::checked_div`]
|
||||
- [`MaybeUninit::as_ptr`]
|
||||
- [`MaybeUninit::as_mut_ptr`]
|
||||
- [`MaybeUninit::assume_init`]
|
||||
- [`MaybeUninit::assume_init_ref`]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- [Add --message-format for install command][cargo/10107]
|
||||
- [Warn when alias shadows external subcommand][cargo/10082]
|
||||
|
||||
Rustdoc
|
||||
-------
|
||||
|
||||
- [Show all Deref implementations recursively in rustdoc][90183]
|
||||
- [Use computed visibility in rustdoc][88447]
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- [Try all stable method candidates first before trying unstable ones][90329]. This change ensures that adding new nightly-only methods to the Rust standard library will not break code invoking methods of the same name from traits outside the standard library.
|
||||
- Windows: [`std::process::Command` will no longer search the current directory for executables.][87704]
|
||||
- [All proc-macro backward-compatibility lints are now deny-by-default.][88041]
|
||||
- [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297]
|
||||
- [Refactor weak symbols in std::sys::unix][90846]. This optimizes accesses to glibc functions, by avoiding the use of dlopen. This does not increase the [minimum expected version of glibc](https://doc.rust-lang.org/nightly/rustc/platform-support.html). However, software distributions that use symbol versions to detect library dependencies, and which take weak symbols into account in that analysis, may detect rust binaries as requiring newer versions of glibc.
|
||||
- [rustdoc now rejects some unexpected semicolons in doctests][91026]
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes provide no direct user facing benefits, but represent significant
|
||||
improvements to the internals and overall performance of rustc
|
||||
and related tools.
|
||||
|
||||
- [Implement coherence checks for negative trait impls][90104]
|
||||
- [Add rustc lint, warning when iterating over hashmaps][89558]
|
||||
- [Optimize live point computation][90491]
|
||||
- [Enable verification for 1/32nd of queries loaded from disk][90361]
|
||||
- [Implement version of normalize_erasing_regions that allows for normalization failure][91255]
|
||||
|
||||
[87337]: https://github.com/rust-lang/rust/pull/87337/
|
||||
[87467]: https://github.com/rust-lang/rust/pull/87467/
|
||||
[87704]: https://github.com/rust-lang/rust/pull/87704/
|
||||
[88041]: https://github.com/rust-lang/rust/pull/88041/
|
||||
[88300]: https://github.com/rust-lang/rust/pull/88300/
|
||||
[88447]: https://github.com/rust-lang/rust/pull/88447/
|
||||
[88601]: https://github.com/rust-lang/rust/pull/88601/
|
||||
[88624]: https://github.com/rust-lang/rust/pull/88624/
|
||||
[89062]: https://github.com/rust-lang/rust/pull/89062/
|
||||
[89174]: https://github.com/rust-lang/rust/pull/89174/
|
||||
[89542]: https://github.com/rust-lang/rust/pull/89542/
|
||||
[89551]: https://github.com/rust-lang/rust/pull/89551/
|
||||
[89558]: https://github.com/rust-lang/rust/pull/89558/
|
||||
[89580]: https://github.com/rust-lang/rust/pull/89580/
|
||||
[89652]: https://github.com/rust-lang/rust/pull/89652/
|
||||
[89677]: https://github.com/rust-lang/rust/pull/89677/
|
||||
[89951]: https://github.com/rust-lang/rust/pull/89951/
|
||||
[90041]: https://github.com/rust-lang/rust/pull/90041/
|
||||
[90058]: https://github.com/rust-lang/rust/pull/90058/
|
||||
[90104]: https://github.com/rust-lang/rust/pull/90104/
|
||||
[90117]: https://github.com/rust-lang/rust/pull/90117/
|
||||
[90175]: https://github.com/rust-lang/rust/pull/90175/
|
||||
[90183]: https://github.com/rust-lang/rust/pull/90183/
|
||||
[90297]: https://github.com/rust-lang/rust/pull/90297/
|
||||
[90329]: https://github.com/rust-lang/rust/pull/90329/
|
||||
[90361]: https://github.com/rust-lang/rust/pull/90361/
|
||||
[90417]: https://github.com/rust-lang/rust/pull/90417/
|
||||
[90473]: https://github.com/rust-lang/rust/pull/90473/
|
||||
[90491]: https://github.com/rust-lang/rust/pull/90491/
|
||||
[90733]: https://github.com/rust-lang/rust/pull/90733/
|
||||
[90833]: https://github.com/rust-lang/rust/pull/90833/
|
||||
[90846]: https://github.com/rust-lang/rust/pull/90846/
|
||||
[90896]: https://github.com/rust-lang/rust/pull/90896/
|
||||
[91026]: https://github.com/rust-lang/rust/pull/91026/
|
||||
[91207]: https://github.com/rust-lang/rust/pull/91207/
|
||||
[91255]: https://github.com/rust-lang/rust/pull/91255/
|
||||
[91301]: https://github.com/rust-lang/rust/pull/91301/
|
||||
[cargo/10082]: https://github.com/rust-lang/cargo/pull/10082/
|
||||
[cargo/10107]: https://github.com/rust-lang/cargo/pull/10107/
|
||||
[`Metadata::is_symlink`]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html#method.is_symlink
|
||||
[`Path::is_symlink`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.is_symlink
|
||||
[`{integer}::saturating_div`]: https://doc.rust-lang.org/stable/std/primitive.i8.html#method.saturating_div
|
||||
[`Option::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_unchecked
|
||||
[`Result::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_unchecked
|
||||
[`Result::unwrap_err_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_err_unchecked
|
||||
[`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two
|
||||
[`File::options`]: https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.options
|
||||
[`unix::process::ExitStatusExt::core_dumped`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.core_dumped
|
||||
[`unix::process::ExitStatusExt::stopped_signal`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.stopped_signal
|
||||
[`unix::process::ExitStatusExt::continued`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.continued
|
||||
[`unix::process::ExitStatusExt::into_raw`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.into_raw
|
||||
[`Duration::new`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.new
|
||||
[`Duration::checked_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_add
|
||||
[`Duration::saturating_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_add
|
||||
[`Duration::checked_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_sub
|
||||
[`Duration::saturating_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_sub
|
||||
[`Duration::checked_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_mul
|
||||
[`Duration::saturating_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_mul
|
||||
[`Duration::checked_div`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_div
|
||||
[`Duration::as_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f64
|
||||
[`Duration::as_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f32
|
||||
[`Duration::from_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f64
|
||||
[`Duration::from_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f32
|
||||
[`Duration::mul_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f64
|
||||
[`Duration::mul_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f32
|
||||
[`Duration::div_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f64
|
||||
[`Duration::div_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f32
|
||||
[`Duration::div_duration_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f64
|
||||
[`Duration::div_duration_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f32
|
||||
[`MaybeUninit::as_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_ptr
|
||||
[`MaybeUninit::as_mut_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_mut_ptr
|
||||
[`MaybeUninit::assume_init`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init
|
||||
[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref
|
||||
|
||||
Version 1.57.0 (2021-12-02)
|
||||
==========================
|
||||
|
||||
@ -388,6 +575,10 @@ Compatibility Notes
|
||||
`Command` would cause them to be ASCII-uppercased.
|
||||
- [Rustdoc will now warn on using rustdoc lints that aren't prefixed
|
||||
with `rustdoc::`][86849]
|
||||
- `RUSTFLAGS` is no longer set for build scripts. Build scripts
|
||||
should use `CARGO_ENCODED_RUSTFLAGS` instead. See the
|
||||
[documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts)
|
||||
for more details.
|
||||
|
||||
[86849]: https://github.com/rust-lang/rust/pull/86849
|
||||
[86513]: https://github.com/rust-lang/rust/pull/86513
|
||||
|
||||
@ -389,7 +389,6 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> {
|
||||
let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
|
||||
|
||||
// Change the exponent from 2^e to 10^e.
|
||||
#[allow(clippy::comparison_chain)]
|
||||
if exp == 0 {
|
||||
// Nothing to do.
|
||||
} else if exp > 0 {
|
||||
@ -2527,7 +2526,6 @@ mod sig {
|
||||
if *a_sign ^ b_sign {
|
||||
let (reverse, loss);
|
||||
|
||||
#[allow(clippy::comparison_chain)]
|
||||
if bits == 0 {
|
||||
reverse = cmp(a_sig, b_sig) == Ordering::Less;
|
||||
loss = Loss::ExactlyZero;
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
use rustc_data_structures::sync;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use std::alloc::Layout;
|
||||
@ -112,7 +111,7 @@ impl<T> Default for TypedArena<T> {
|
||||
// alloc() will trigger a grow().
|
||||
ptr: Cell::new(ptr::null_mut()),
|
||||
end: Cell::new(ptr::null_mut()),
|
||||
chunks: RefCell::new(vec![]),
|
||||
chunks: Default::default(),
|
||||
_own: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -326,13 +325,17 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
|
||||
|
||||
unsafe impl<T: Send> Send for TypedArena<T> {}
|
||||
|
||||
/// An arena that can hold objects of multiple different types that impl `Copy`
|
||||
/// and/or satisfy `!mem::needs_drop`.
|
||||
pub struct DroplessArena {
|
||||
/// A pointer to the start of the free space.
|
||||
start: Cell<*mut u8>,
|
||||
|
||||
/// A pointer to the end of free space.
|
||||
///
|
||||
/// The allocation proceeds from the end of the chunk towards the start.
|
||||
/// The allocation proceeds downwards from the end of the chunk towards the
|
||||
/// start. (This is slightly simpler and faster than allocating upwards,
|
||||
/// see <https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html>.)
|
||||
/// When this pointer crosses the start pointer, a new chunk is allocated.
|
||||
end: Cell<*mut u8>,
|
||||
|
||||
@ -517,130 +520,16 @@ impl DroplessArena {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls the destructor for an object when dropped.
|
||||
struct DropType {
|
||||
drop_fn: unsafe fn(*mut u8),
|
||||
obj: *mut u8,
|
||||
}
|
||||
|
||||
// SAFETY: we require `T: Send` before type-erasing into `DropType`.
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl sync::Send for DropType {}
|
||||
|
||||
impl DropType {
|
||||
#[inline]
|
||||
unsafe fn new<T: sync::Send>(obj: *mut T) -> Self {
|
||||
unsafe fn drop_for_type<T>(to_drop: *mut u8) {
|
||||
std::ptr::drop_in_place(to_drop as *mut T)
|
||||
}
|
||||
|
||||
DropType { drop_fn: drop_for_type::<T>, obj: obj as *mut u8 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DropType {
|
||||
fn drop(&mut self) {
|
||||
unsafe { (self.drop_fn)(self.obj) }
|
||||
}
|
||||
}
|
||||
|
||||
/// An arena which can be used to allocate any type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Allocating in this arena is unsafe since the type system
|
||||
/// doesn't know which types it contains. In order to
|
||||
/// allocate safely, you must store a `PhantomData<T>`
|
||||
/// alongside this arena for each type `T` you allocate.
|
||||
#[derive(Default)]
|
||||
pub struct DropArena {
|
||||
/// A list of destructors to run when the arena drops.
|
||||
/// Ordered so `destructors` gets dropped before the arena
|
||||
/// since its destructor can reference memory in the arena.
|
||||
destructors: RefCell<Vec<DropType>>,
|
||||
arena: DroplessArena,
|
||||
}
|
||||
|
||||
impl DropArena {
|
||||
#[inline]
|
||||
pub unsafe fn alloc<T>(&self, object: T) -> &mut T
|
||||
where
|
||||
T: sync::Send,
|
||||
{
|
||||
let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T;
|
||||
// Write into uninitialized memory.
|
||||
ptr::write(mem, object);
|
||||
let result = &mut *mem;
|
||||
// Record the destructor after doing the allocation as that may panic
|
||||
// and would cause `object`'s destructor to run twice if it was recorded before.
|
||||
self.destructors.borrow_mut().push(DropType::new(result));
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn alloc_from_iter<T, I>(&self, iter: I) -> &mut [T]
|
||||
where
|
||||
T: sync::Send,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
|
||||
if vec.is_empty() {
|
||||
return &mut [];
|
||||
}
|
||||
let len = vec.len();
|
||||
|
||||
let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
|
||||
|
||||
let mut destructors = self.destructors.borrow_mut();
|
||||
// Reserve space for the destructors so we can't panic while adding them.
|
||||
destructors.reserve(len);
|
||||
|
||||
// Move the content to the arena by copying it and then forgetting
|
||||
// the content of the SmallVec.
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
mem::forget(vec.drain(..));
|
||||
|
||||
// Record the destructors after doing the allocation as that may panic
|
||||
// and would cause `object`'s destructor to run twice if it was recorded before.
|
||||
for i in 0..len {
|
||||
destructors.push(DropType::new(start_ptr.add(i)));
|
||||
}
|
||||
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
pub macro arena_for_type {
|
||||
([][$ty:ty]) => {
|
||||
$crate::TypedArena<$ty>
|
||||
},
|
||||
([few $(, $attrs:ident)*][$ty:ty]) => {
|
||||
::std::marker::PhantomData<$ty>
|
||||
},
|
||||
([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
|
||||
$crate::arena_for_type!([$($attrs),*]$args)
|
||||
},
|
||||
}
|
||||
|
||||
pub macro which_arena_for_type {
|
||||
([][$arena:expr]) => {
|
||||
::std::option::Option::Some($arena)
|
||||
},
|
||||
([few$(, $attrs:ident)*][$arena:expr]) => {
|
||||
::std::option::Option::None
|
||||
},
|
||||
([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
|
||||
$crate::which_arena_for_type!([$($attrs),*]$args)
|
||||
},
|
||||
}
|
||||
|
||||
// Declare an `Arena` containing one dropless arena and many typed arenas (the
|
||||
// types of the typed arenas are specified by the arguments). The dropless
|
||||
// arena will be used for any types that impl `Copy`, and also for any of the
|
||||
// specified types that satisfy `!mem::needs_drop`.
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
|
||||
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
|
||||
#[derive(Default)]
|
||||
pub struct Arena<$tcx> {
|
||||
pub struct Arena<'tcx> {
|
||||
pub dropless: $crate::DroplessArena,
|
||||
drop: $crate::DropArena,
|
||||
$($name: $crate::arena_for_type!($a[$ty]),)*
|
||||
$($name: $crate::TypedArena<$ty>,)*
|
||||
}
|
||||
|
||||
pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
|
||||
@ -651,6 +540,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
|
||||
) -> &'a mut [Self];
|
||||
}
|
||||
|
||||
// Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
|
||||
impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
|
||||
#[inline]
|
||||
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
|
||||
@ -663,36 +553,27 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
|
||||
) -> &'a mut [Self] {
|
||||
arena.dropless.alloc_from_iter(iter)
|
||||
}
|
||||
|
||||
}
|
||||
$(
|
||||
impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
|
||||
impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty {
|
||||
#[inline]
|
||||
fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
|
||||
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
|
||||
if !::std::mem::needs_drop::<Self>() {
|
||||
return arena.dropless.alloc(self);
|
||||
}
|
||||
match $crate::which_arena_for_type!($a[&arena.$name]) {
|
||||
::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
|
||||
ty_arena.alloc(self)
|
||||
}
|
||||
::std::option::Option::None => unsafe { arena.drop.alloc(self) },
|
||||
arena.dropless.alloc(self)
|
||||
} else {
|
||||
arena.$name.alloc(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn allocate_from_iter<'a>(
|
||||
arena: &'a Arena<$tcx>,
|
||||
arena: &'a Arena<'tcx>,
|
||||
iter: impl ::std::iter::IntoIterator<Item = Self>,
|
||||
) -> &'a mut [Self] {
|
||||
if !::std::mem::needs_drop::<Self>() {
|
||||
return arena.dropless.alloc_from_iter(iter);
|
||||
}
|
||||
match $crate::which_arena_for_type!($a[&arena.$name]) {
|
||||
::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
|
||||
ty_arena.alloc_from_iter(iter)
|
||||
}
|
||||
::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
|
||||
arena.dropless.alloc_from_iter(iter)
|
||||
} else {
|
||||
arena.$name.alloc_from_iter(iter)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -704,6 +585,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
|
||||
value.allocate_on(self)
|
||||
}
|
||||
|
||||
// Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`.
|
||||
#[inline]
|
||||
pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
|
||||
if value.is_empty() {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
The `rustc_ast` crate contains those things concerned purely with syntax
|
||||
– that is, the AST ("abstract syntax tree"), parser, pretty-printer,
|
||||
lexer, macro expander, and utilities for traversing ASTs.
|
||||
– that is, the AST ("abstract syntax tree"), along with some definitions for tokens and token streams, data structures/traits for mutating ASTs, and shared definitions for other AST-related parts of the compiler (like the lexer and macro-expansion).
|
||||
|
||||
For more information about how these things work in rustc, see the
|
||||
rustc dev guide:
|
||||
|
||||
@ -405,6 +405,21 @@ pub struct GenericParam {
|
||||
pub kind: GenericParamKind,
|
||||
}
|
||||
|
||||
impl GenericParam {
|
||||
pub fn span(&self) -> Span {
|
||||
match &self.kind {
|
||||
GenericParamKind::Lifetime | GenericParamKind::Type { default: None } => {
|
||||
self.ident.span
|
||||
}
|
||||
GenericParamKind::Type { default: Some(ty) } => self.ident.span.to(ty.span),
|
||||
GenericParamKind::Const { kw_span, default: Some(default), .. } => {
|
||||
kw_span.to(default.value.span)
|
||||
}
|
||||
GenericParamKind::Const { kw_span, default: None, ty } => kw_span.to(ty.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents lifetime, type and const parameters attached to a declaration of
|
||||
/// a function, enum, trait, etc.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
@ -2058,7 +2073,7 @@ pub struct InlineAsm {
|
||||
pub template: Vec<InlineAsmTemplatePiece>,
|
||||
pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
|
||||
pub operands: Vec<(InlineAsmOperand, Span)>,
|
||||
pub clobber_abi: Option<(Symbol, Span)>,
|
||||
pub clobber_abis: Vec<(Symbol, Span)>,
|
||||
pub options: InlineAsmOptions,
|
||||
pub line_spans: Vec<Span>,
|
||||
}
|
||||
@ -2645,34 +2660,42 @@ impl Default for FnHeader {
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct TraitKind(
|
||||
pub IsAuto,
|
||||
pub Unsafe,
|
||||
pub Generics,
|
||||
pub GenericBounds,
|
||||
pub Vec<P<AssocItem>>,
|
||||
);
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct TyAliasKind(pub Defaultness, pub Generics, pub GenericBounds, pub Option<P<Ty>>);
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct ImplKind {
|
||||
pub struct Trait {
|
||||
pub unsafety: Unsafe,
|
||||
pub polarity: ImplPolarity,
|
||||
pub defaultness: Defaultness,
|
||||
pub constness: Const,
|
||||
pub is_auto: IsAuto,
|
||||
pub generics: Generics,
|
||||
pub bounds: GenericBounds,
|
||||
pub items: Vec<P<AssocItem>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct TyAlias {
|
||||
pub defaultness: Defaultness,
|
||||
pub generics: Generics,
|
||||
pub bounds: GenericBounds,
|
||||
pub ty: Option<P<Ty>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Impl {
|
||||
pub defaultness: Defaultness,
|
||||
pub unsafety: Unsafe,
|
||||
pub generics: Generics,
|
||||
pub constness: Const,
|
||||
pub polarity: ImplPolarity,
|
||||
/// The trait being implemented, if any.
|
||||
pub of_trait: Option<TraitRef>,
|
||||
|
||||
pub self_ty: P<Ty>,
|
||||
pub items: Vec<P<AssocItem>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct FnKind(pub Defaultness, pub FnSig, pub Generics, pub Option<P<Block>>);
|
||||
pub struct Fn {
|
||||
pub defaultness: Defaultness,
|
||||
pub generics: Generics,
|
||||
pub sig: FnSig,
|
||||
pub body: Option<P<Block>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ItemKind {
|
||||
@ -2695,7 +2718,7 @@ pub enum ItemKind {
|
||||
/// A function declaration (`fn`).
|
||||
///
|
||||
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
||||
Fn(Box<FnKind>),
|
||||
Fn(Box<Fn>),
|
||||
/// A module declaration (`mod`).
|
||||
///
|
||||
/// E.g., `mod foo;` or `mod foo { .. }`.
|
||||
@ -2707,11 +2730,11 @@ pub enum ItemKind {
|
||||
/// E.g., `extern {}` or `extern "C" {}`.
|
||||
ForeignMod(ForeignMod),
|
||||
/// Module-level inline assembly (from `global_asm!()`).
|
||||
GlobalAsm(InlineAsm),
|
||||
GlobalAsm(Box<InlineAsm>),
|
||||
/// A type alias (`type`).
|
||||
///
|
||||
/// E.g., `type Foo = Bar<u8>;`.
|
||||
TyAlias(Box<TyAliasKind>),
|
||||
TyAlias(Box<TyAlias>),
|
||||
/// An enum definition (`enum`).
|
||||
///
|
||||
/// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
|
||||
@ -2727,7 +2750,7 @@ pub enum ItemKind {
|
||||
/// A trait declaration (`trait`).
|
||||
///
|
||||
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
|
||||
Trait(Box<TraitKind>),
|
||||
Trait(Box<Trait>),
|
||||
/// Trait alias
|
||||
///
|
||||
/// E.g., `trait Foo = Bar + Quux;`.
|
||||
@ -2735,7 +2758,7 @@ pub enum ItemKind {
|
||||
/// An implementation.
|
||||
///
|
||||
/// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
|
||||
Impl(Box<ImplKind>),
|
||||
Impl(Box<Impl>),
|
||||
/// A macro invocation.
|
||||
///
|
||||
/// E.g., `foo!(..)`.
|
||||
@ -2782,14 +2805,14 @@ impl ItemKind {
|
||||
|
||||
pub fn generics(&self) -> Option<&Generics> {
|
||||
match self {
|
||||
Self::Fn(box FnKind(_, _, generics, _))
|
||||
| Self::TyAlias(box TyAliasKind(_, generics, ..))
|
||||
Self::Fn(box Fn { generics, .. })
|
||||
| Self::TyAlias(box TyAlias { generics, .. })
|
||||
| Self::Enum(_, generics)
|
||||
| Self::Struct(_, generics)
|
||||
| Self::Union(_, generics)
|
||||
| Self::Trait(box TraitKind(_, _, generics, ..))
|
||||
| Self::Trait(box Trait { generics, .. })
|
||||
| Self::TraitAlias(generics, _)
|
||||
| Self::Impl(box ImplKind { generics, .. }) => Some(generics),
|
||||
| Self::Impl(box Impl { generics, .. }) => Some(generics),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -2812,9 +2835,9 @@ pub enum AssocItemKind {
|
||||
/// If `def` is parsed, then the constant is provided, and otherwise required.
|
||||
Const(Defaultness, P<Ty>, Option<P<Expr>>),
|
||||
/// An associated function.
|
||||
Fn(Box<FnKind>),
|
||||
Fn(Box<Fn>),
|
||||
/// An associated type.
|
||||
TyAlias(Box<TyAliasKind>),
|
||||
TyAlias(Box<TyAlias>),
|
||||
/// A macro expanding to associated items.
|
||||
MacCall(MacCall),
|
||||
}
|
||||
@ -2825,9 +2848,9 @@ rustc_data_structures::static_assert_size!(AssocItemKind, 72);
|
||||
impl AssocItemKind {
|
||||
pub fn defaultness(&self) -> Defaultness {
|
||||
match *self {
|
||||
Self::Const(def, ..)
|
||||
| Self::Fn(box FnKind(def, ..))
|
||||
| Self::TyAlias(box TyAliasKind(def, ..)) => def,
|
||||
Self::Const(defaultness, ..)
|
||||
| Self::Fn(box Fn { defaultness, .. })
|
||||
| Self::TyAlias(box TyAlias { defaultness, .. }) => defaultness,
|
||||
Self::MacCall(..) => Defaultness::Final,
|
||||
}
|
||||
}
|
||||
@ -2864,9 +2887,9 @@ pub enum ForeignItemKind {
|
||||
/// A foreign static item (`static FOO: u8`).
|
||||
Static(P<Ty>, Mutability, Option<P<Expr>>),
|
||||
/// An foreign function.
|
||||
Fn(Box<FnKind>),
|
||||
Fn(Box<Fn>),
|
||||
/// An foreign type.
|
||||
TyAlias(Box<TyAliasKind>),
|
||||
TyAlias(Box<TyAlias>),
|
||||
/// A macro expanding to foreign items.
|
||||
MacCall(MacCall),
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ impl NestedMetaItem {
|
||||
self.meta_item().and_then(|meta_item| meta_item.ident())
|
||||
}
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::invalid).name
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
}
|
||||
|
||||
/// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
|
||||
@ -131,7 +131,7 @@ impl Attribute {
|
||||
}
|
||||
}
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::invalid).name
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
}
|
||||
|
||||
pub fn value_str(&self) -> Option<Symbol> {
|
||||
@ -166,7 +166,7 @@ impl MetaItem {
|
||||
if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
|
||||
}
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::invalid).name
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
}
|
||||
|
||||
// Example:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
//! The Rust parser and macro expander.
|
||||
//! The Rust Abstract Syntax Tree (AST).
|
||||
//!
|
||||
//! # Note
|
||||
//!
|
||||
@ -16,6 +16,7 @@
|
||||
#![feature(nll)]
|
||||
#![feature(min_specialization)]
|
||||
#![recursion_limit = "256"]
|
||||
#![feature(slice_internals)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
@ -25,6 +26,7 @@ pub mod util {
|
||||
pub mod comments;
|
||||
pub mod literal;
|
||||
pub mod parser;
|
||||
pub mod unicode;
|
||||
}
|
||||
|
||||
pub mod ast;
|
||||
|
||||
@ -37,9 +37,7 @@ pub trait MutVisitor: Sized {
|
||||
/// Mutable token visiting only exists for the `macro_rules` token marker and should not be
|
||||
/// used otherwise. Token visitor would be entirely separate from the regular visitor if
|
||||
/// the marker didn't have to visit AST fragments in nonterminal tokens.
|
||||
fn token_visiting_enabled(&self) -> bool {
|
||||
false
|
||||
}
|
||||
const VISIT_TOKENS: bool = false;
|
||||
|
||||
// Methods in this trait have one of three forms:
|
||||
//
|
||||
@ -363,7 +361,7 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
|
||||
}
|
||||
MacArgs::Eq(eq_span, token) => {
|
||||
vis.visit_span(eq_span);
|
||||
if vis.token_visiting_enabled() {
|
||||
if T::VISIT_TOKENS {
|
||||
visit_token(token, vis);
|
||||
} else {
|
||||
// The value in `#[key = VALUE]` must be visited as an expression for backward
|
||||
@ -461,7 +459,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
||||
vis.visit_mt(mt);
|
||||
}
|
||||
TyKind::BareFn(bft) => {
|
||||
let BareFnTy { unsafety: _, ext: _, generic_params, decl } = bft.deref_mut();
|
||||
let BareFnTy { unsafety, ext: _, generic_params, decl } = bft.deref_mut();
|
||||
visit_unsafety(unsafety, vis);
|
||||
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_fn_decl(decl);
|
||||
}
|
||||
@ -490,7 +489,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
||||
}
|
||||
|
||||
pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
|
||||
let ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
|
||||
let ForeignMod { unsafety, abi: _, items } = foreign_mod;
|
||||
visit_unsafety(unsafety, vis);
|
||||
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
|
||||
}
|
||||
|
||||
@ -682,7 +682,7 @@ pub fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
|
||||
if vis.token_visiting_enabled() && !tts.is_empty() {
|
||||
if T::VISIT_TOKENS && !tts.is_empty() {
|
||||
let tts = Lrc::make_mut(tts);
|
||||
visit_vec(tts, |(tree, _is_joint)| visit_tt(tree, vis));
|
||||
}
|
||||
@ -692,14 +692,14 @@ pub fn visit_attr_annotated_tts<T: MutVisitor>(
|
||||
AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
|
||||
vis: &mut T,
|
||||
) {
|
||||
if vis.token_visiting_enabled() && !tts.is_empty() {
|
||||
if T::VISIT_TOKENS && !tts.is_empty() {
|
||||
let tts = Lrc::make_mut(tts);
|
||||
visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
|
||||
if vis.token_visiting_enabled() {
|
||||
if T::VISIT_TOKENS {
|
||||
if let Some(lazy_tts) = lazy_tts {
|
||||
let mut tts = lazy_tts.create_token_stream();
|
||||
visit_attr_annotated_tts(&mut tts, vis);
|
||||
@ -790,6 +790,38 @@ pub fn visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) {
|
||||
match defaultness {
|
||||
Defaultness::Default(span) => vis.visit_span(span),
|
||||
Defaultness::Final => {}
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) {
|
||||
match unsafety {
|
||||
Unsafe::Yes(span) => vis.visit_span(span),
|
||||
Unsafe::No => {}
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) {
|
||||
match polarity {
|
||||
ImplPolarity::Positive => {}
|
||||
ImplPolarity::Negative(span) => vis.visit_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
|
||||
match constness {
|
||||
Const::Yes(span) => vis.visit_span(span),
|
||||
Const::No => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
|
||||
match asyncness {
|
||||
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
|
||||
@ -957,25 +989,35 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
match kind {
|
||||
ItemKind::ExternCrate(_orig_name) => {}
|
||||
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
||||
ItemKind::Static(ty, _, expr) | ItemKind::Const(_, ty, expr) => {
|
||||
ItemKind::Static(ty, _, expr) => {
|
||||
vis.visit_ty(ty);
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ItemKind::Fn(box FnKind(_, sig, generics, body)) => {
|
||||
ItemKind::Const(defaultness, ty, expr) => {
|
||||
visit_defaultness(defaultness, vis);
|
||||
vis.visit_ty(ty);
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(defaultness, vis);
|
||||
visit_fn_sig(sig, vis);
|
||||
vis.visit_generics(generics);
|
||||
visit_opt(body, |body| vis.visit_block(body));
|
||||
}
|
||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _inline, inner_span) => {
|
||||
vis.visit_span(inner_span);
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
ItemKind::Mod(unsafety, mod_kind) => {
|
||||
visit_unsafety(unsafety, vis);
|
||||
match mod_kind {
|
||||
ModKind::Loaded(items, _inline, inner_span) => {
|
||||
vis.visit_span(inner_span);
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
}
|
||||
ModKind::Unloaded => {}
|
||||
}
|
||||
ModKind::Unloaded => {}
|
||||
},
|
||||
}
|
||||
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
|
||||
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
|
||||
ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
|
||||
ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
visit_defaultness(defaultness, vis);
|
||||
vis.visit_generics(generics);
|
||||
visit_bounds(bounds, vis);
|
||||
visit_opt(ty, |ty| vis.visit_ty(ty));
|
||||
@ -988,22 +1030,27 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
vis.visit_variant_data(variant_data);
|
||||
vis.visit_generics(generics);
|
||||
}
|
||||
ItemKind::Impl(box ImplKind {
|
||||
unsafety: _,
|
||||
polarity: _,
|
||||
defaultness: _,
|
||||
constness: _,
|
||||
ItemKind::Impl(box Impl {
|
||||
defaultness,
|
||||
unsafety,
|
||||
generics,
|
||||
constness,
|
||||
polarity,
|
||||
of_trait,
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
visit_defaultness(defaultness, vis);
|
||||
visit_unsafety(unsafety, vis);
|
||||
vis.visit_generics(generics);
|
||||
visit_constness(constness, vis);
|
||||
visit_polarity(polarity, vis);
|
||||
visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref));
|
||||
vis.visit_ty(self_ty);
|
||||
items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
|
||||
}
|
||||
ItemKind::Trait(box TraitKind(.., generics, bounds, items)) => {
|
||||
ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => {
|
||||
visit_unsafety(unsafety, vis);
|
||||
vis.visit_generics(generics);
|
||||
visit_bounds(bounds, vis);
|
||||
items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
|
||||
@ -1027,16 +1074,19 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
|
||||
visitor.visit_vis(vis);
|
||||
visit_attrs(attrs, visitor);
|
||||
match kind {
|
||||
AssocItemKind::Const(_, ty, expr) => {
|
||||
AssocItemKind::Const(defaultness, ty, expr) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(expr, |expr| visitor.visit_expr(expr));
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
|
||||
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visit_fn_sig(sig, visitor);
|
||||
visit_opt(body, |body| visitor.visit_block(body));
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
|
||||
AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visit_bounds(bounds, visitor);
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
@ -1049,8 +1099,10 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
|
||||
}
|
||||
|
||||
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
|
||||
let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header;
|
||||
let FnHeader { unsafety, asyncness, constness, ext: _ } = header;
|
||||
visit_constness(constness, vis);
|
||||
vis.visit_asyncness(asyncness);
|
||||
visit_unsafety(unsafety, vis);
|
||||
}
|
||||
|
||||
// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
|
||||
@ -1060,7 +1112,7 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
|
||||
let item_vis =
|
||||
Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
|
||||
let item = P(Item {
|
||||
ident: Ident::invalid(),
|
||||
ident: Ident::empty(),
|
||||
attrs,
|
||||
id: DUMMY_NODE_ID,
|
||||
vis: item_vis,
|
||||
@ -1116,12 +1168,14 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(expr, |expr| visitor.visit_expr(expr));
|
||||
}
|
||||
ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
|
||||
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visit_fn_sig(sig, visitor);
|
||||
visit_opt(body, |body| visitor.visit_block(body));
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
|
||||
ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visit_bounds(bounds, visitor);
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
|
||||
@ -221,12 +221,6 @@ impl AttrAnnotatedTokenStream {
|
||||
for attr in &data.attrs {
|
||||
match attr.style {
|
||||
crate::AttrStyle::Outer => {
|
||||
assert!(
|
||||
inner_attrs.len() == 0,
|
||||
"Found outer attribute {:?} after inner attrs {:?}",
|
||||
attr,
|
||||
inner_attrs
|
||||
);
|
||||
outer_attrs.push(attr);
|
||||
}
|
||||
crate::AttrStyle::Inner => {
|
||||
|
||||
@ -38,7 +38,7 @@ pub fn beautify_doc_string(data: Symbol) -> Symbol {
|
||||
i += 1;
|
||||
}
|
||||
// like the first, a last line of all stars should be omitted
|
||||
if j > i && lines[j - 1].chars().skip(1).all(|c| c == '*') {
|
||||
if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
|
||||
j -= 1;
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
|
||||
if let Some(mut idx) = token_text.find('\n') {
|
||||
code_to_the_left = false;
|
||||
while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
|
||||
idx = idx + 1 + next_newline;
|
||||
idx += 1 + next_newline;
|
||||
comments.push(Comment {
|
||||
style: CommentStyle::BlankLine,
|
||||
lines: vec![],
|
||||
|
||||
@ -212,7 +212,8 @@ impl AssocOp {
|
||||
/// parentheses while having a high degree of confidence on the correctness of the suggestion.
|
||||
pub fn can_continue_expr_unambiguously(&self) -> bool {
|
||||
use AssocOp::*;
|
||||
match self {
|
||||
matches!(
|
||||
self,
|
||||
BitXor | // `{ 42 } ^ 3`
|
||||
Assign | // `{ 42 } = { 42 }`
|
||||
Divide | // `{ 42 } / 42`
|
||||
@ -225,9 +226,8 @@ impl AssocOp {
|
||||
As | // `{ 42 } as usize`
|
||||
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
|
||||
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
|
||||
Colon => true, // `{ 42 }: usize`
|
||||
_ => false,
|
||||
}
|
||||
Colon, // `{ 42 }: usize`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,13 +357,13 @@ impl ExprPrecedence {
|
||||
}
|
||||
}
|
||||
|
||||
/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
|
||||
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
|
||||
pub fn prec_let_scrutinee_needs_par() -> usize {
|
||||
AssocOp::LAnd.precedence()
|
||||
}
|
||||
|
||||
/// Suppose we have `let _ = e` and the `order` of `e`.
|
||||
/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
|
||||
/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
|
||||
///
|
||||
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
|
||||
/// Can we print this as `let _ = a OP b`?
|
||||
|
||||
35
compiler/rustc_ast/src/util/unicode.rs
Normal file
35
compiler/rustc_ast/src/util/unicode.rs
Normal file
@ -0,0 +1,35 @@
|
||||
pub const TEXT_FLOW_CONTROL_CHARS: &[char] = &[
|
||||
'\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}',
|
||||
'\u{2069}',
|
||||
];
|
||||
|
||||
#[inline]
|
||||
pub fn contains_text_flow_control_chars(s: &str) -> bool {
|
||||
// Char - UTF-8
|
||||
// U+202A - E2 80 AA
|
||||
// U+202B - E2 80 AB
|
||||
// U+202C - E2 80 AC
|
||||
// U+202D - E2 80 AD
|
||||
// U+202E - E2 80 AE
|
||||
// U+2066 - E2 81 A6
|
||||
// U+2067 - E2 81 A7
|
||||
// U+2068 - E2 81 A8
|
||||
// U+2069 - E2 81 A9
|
||||
let mut bytes = s.as_bytes();
|
||||
loop {
|
||||
match core::slice::memchr::memchr(0xE2, &bytes) {
|
||||
Some(idx) => {
|
||||
// bytes are valid UTF-8 -> E2 must be followed by two bytes
|
||||
let ch = &bytes[idx..idx + 3];
|
||||
match ch {
|
||||
[_, 0x80, 0xAA..=0xAE] | [_, 0x81, 0xA6..=0xA9] => break true,
|
||||
_ => {}
|
||||
}
|
||||
bytes = &bytes[idx + 3..];
|
||||
}
|
||||
None => {
|
||||
break false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,7 +285,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
visitor.visit_ty(typ);
|
||||
walk_list!(visitor, visit_expr, expr);
|
||||
}
|
||||
ItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) => {
|
||||
ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
|
||||
visitor.visit_generics(generics);
|
||||
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
|
||||
visitor.visit_fn(kind, item.span, item.id)
|
||||
@ -300,7 +300,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
|
||||
}
|
||||
ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
|
||||
ItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty)) => {
|
||||
ItemKind::TyAlias(box TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => {
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_ty, ty);
|
||||
@ -309,12 +309,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
|
||||
}
|
||||
ItemKind::Impl(box ImplKind {
|
||||
unsafety: _,
|
||||
polarity: _,
|
||||
ItemKind::Impl(box Impl {
|
||||
defaultness: _,
|
||||
constness: _,
|
||||
unsafety: _,
|
||||
ref generics,
|
||||
constness: _,
|
||||
polarity: _,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
ref items,
|
||||
@ -329,7 +329,13 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_variant_data(struct_definition);
|
||||
}
|
||||
ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref items)) => {
|
||||
ItemKind::Trait(box Trait {
|
||||
unsafety: _,
|
||||
is_auto: _,
|
||||
ref generics,
|
||||
ref bounds,
|
||||
ref items,
|
||||
}) => {
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
|
||||
@ -547,12 +553,12 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
|
||||
visitor.visit_ty(ty);
|
||||
walk_list!(visitor, visit_expr, expr);
|
||||
}
|
||||
ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
|
||||
ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
|
||||
visitor.visit_generics(generics);
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
|
||||
visitor.visit_fn(kind, span, id);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
|
||||
ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_ty, ty);
|
||||
@ -653,12 +659,12 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
|
||||
visitor.visit_ty(ty);
|
||||
walk_list!(visitor, visit_expr, expr);
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
|
||||
AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
|
||||
visitor.visit_generics(generics);
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
|
||||
visitor.visit_fn(kind, span, id);
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
|
||||
AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_ty, ty);
|
||||
|
||||
@ -14,6 +14,7 @@ rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
|
||||
@ -2,22 +2,45 @@ use super::LoweringContext;
|
||||
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_set::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_target::asm;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::Write;
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
|
||||
// Rustdoc needs to support asm! from foriegn architectures: don't try
|
||||
// lowering the register contraints in this case.
|
||||
// Rustdoc needs to support asm! from foreign architectures: don't try
|
||||
// lowering the register constraints in this case.
|
||||
let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
|
||||
if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
|
||||
struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
|
||||
.emit();
|
||||
}
|
||||
if let Some(asm_arch) = asm_arch {
|
||||
// Inline assembly is currently only stable for these architectures.
|
||||
let is_stable = matches!(
|
||||
asm_arch,
|
||||
asm::InlineAsmArch::X86
|
||||
| asm::InlineAsmArch::X86_64
|
||||
| asm::InlineAsmArch::Arm
|
||||
| asm::InlineAsmArch::AArch64
|
||||
| asm::InlineAsmArch::RiscV32
|
||||
| asm::InlineAsmArch::RiscV64
|
||||
);
|
||||
if !is_stable && !self.sess.features_untracked().asm_experimental_arch {
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::asm_experimental_arch,
|
||||
sp,
|
||||
"inline assembly is not stable yet on this architecture",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
|
||||
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
|
||||
&& !self.sess.opts.actually_rustdoc
|
||||
@ -27,22 +50,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
let mut clobber_abi = None;
|
||||
let mut clobber_abis = FxHashMap::default();
|
||||
if let Some(asm_arch) = asm_arch {
|
||||
if let Some((abi_name, abi_span)) = asm.clobber_abi {
|
||||
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
|
||||
Ok(abi) => clobber_abi = Some((abi, abi_span)),
|
||||
for (abi_name, abi_span) in &asm.clobber_abis {
|
||||
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
|
||||
Ok(abi) => {
|
||||
// If the abi was already in the list, emit an error
|
||||
match clobber_abis.get(&abi) {
|
||||
Some((prev_name, prev_sp)) => {
|
||||
let mut err = self.sess.struct_span_err(
|
||||
*abi_span,
|
||||
&format!("`{}` ABI specified multiple times", prev_name),
|
||||
);
|
||||
err.span_label(*prev_sp, "previously specified here");
|
||||
|
||||
// Multiple different abi names may actually be the same ABI
|
||||
// If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
|
||||
let source_map = self.sess.source_map();
|
||||
if source_map.span_to_snippet(*prev_sp)
|
||||
!= source_map.span_to_snippet(*abi_span)
|
||||
{
|
||||
err.note("these ABIs are equivalent on the current target");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
None => {
|
||||
clobber_abis.insert(abi, (abi_name, *abi_span));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(&[]) => {
|
||||
self.sess
|
||||
.struct_span_err(
|
||||
abi_span,
|
||||
*abi_span,
|
||||
"`clobber_abi` is not supported on this target",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Err(supported_abis) => {
|
||||
let mut err =
|
||||
self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
|
||||
self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
|
||||
let mut abis = format!("`{}`", supported_abis[0]);
|
||||
for m in &supported_abis[1..] {
|
||||
let _ = write!(abis, ", `{}`", m);
|
||||
@ -121,10 +169,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { ref anon_const } => hir::InlineAsmOperand::Const {
|
||||
anon_const: self.lower_anon_const(anon_const),
|
||||
},
|
||||
InlineAsmOperand::Const { ref anon_const } => {
|
||||
if !self.sess.features_untracked().asm_const {
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::asm_const,
|
||||
*op_sp,
|
||||
"const operands for inline assembly are unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
hir::InlineAsmOperand::Const {
|
||||
anon_const: self.lower_anon_const(anon_const),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Sym { ref expr } => {
|
||||
if !self.sess.features_untracked().asm_sym {
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::asm_sym,
|
||||
*op_sp,
|
||||
"sym operands for inline assembly are unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
|
||||
}
|
||||
};
|
||||
@ -214,9 +282,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// means that we disallow passing a value in/out of the asm and
|
||||
// require that the operand name an explicit register, not a
|
||||
// register class.
|
||||
if reg_class.is_clobber_only(asm_arch.unwrap())
|
||||
&& !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
|
||||
{
|
||||
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
|
||||
let msg = format!(
|
||||
"register class `{}` can only be used as a clobber, \
|
||||
not as an input or output",
|
||||
@ -308,8 +374,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
// If a clobber_abi is specified, add the necessary clobbers to the
|
||||
// operands list.
|
||||
if let Some((abi, abi_span)) = clobber_abi {
|
||||
let mut clobbered = FxHashSet::default();
|
||||
for (abi, (_, abi_span)) in clobber_abis {
|
||||
for &clobber in abi.clobbered_regs() {
|
||||
// Don't emit a clobber for a register already clobbered
|
||||
if clobbered.contains(&clobber) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut output_used = false;
|
||||
clobber.overlapping_regs(|reg| {
|
||||
if used_output_regs.contains_key(®) {
|
||||
@ -326,6 +398,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
},
|
||||
self.lower_span(abi_span),
|
||||
));
|
||||
clobbered.insert(clobber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ use rustc_session::parse::feature_err;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
@ -252,9 +252,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
// Merge attributes into the inner expression.
|
||||
if !e.attrs.is_empty() {
|
||||
let old_attrs = self.attrs.get(&ex.hir_id).map(|la| *la).unwrap_or(&[]);
|
||||
let old_attrs =
|
||||
self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
|
||||
self.attrs.insert(
|
||||
ex.hir_id,
|
||||
ex.hir_id.local_id,
|
||||
&*self.arena.alloc_from_iter(
|
||||
e.attrs
|
||||
.iter()
|
||||
@ -914,14 +915,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
}
|
||||
if !self.sess.features_untracked().destructuring_assignment {
|
||||
feature_err(
|
||||
let mut err = feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::destructuring_assignment,
|
||||
eq_sign_span,
|
||||
"destructuring assignments are unstable",
|
||||
)
|
||||
.span_label(lhs.span, "cannot assign to this expression")
|
||||
.emit();
|
||||
);
|
||||
err.span_label(lhs.span, "cannot assign to this expression");
|
||||
if self.is_in_loop_condition {
|
||||
err.span_suggestion_verbose(
|
||||
lhs.span.shrink_to_lo(),
|
||||
"you might have meant to use pattern destructuring",
|
||||
"let ".to_string(),
|
||||
rustc_errors::Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
let mut assignments = vec![];
|
||||
@ -1307,16 +1316,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
/// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
|
||||
/// ```rust
|
||||
/// {
|
||||
/// let result = match ::std::iter::IntoIterator::into_iter(<head>) {
|
||||
/// let result = match IntoIterator::into_iter(<head>) {
|
||||
/// mut iter => {
|
||||
/// [opt_ident]: loop {
|
||||
/// let mut __next;
|
||||
/// match ::std::iter::Iterator::next(&mut iter) {
|
||||
/// ::std::option::Option::Some(val) => __next = val,
|
||||
/// ::std::option::Option::None => break
|
||||
/// match Iterator::next(&mut iter) {
|
||||
/// None => break,
|
||||
/// Some(<pat>) => <body>,
|
||||
/// };
|
||||
/// let <pat> = __next;
|
||||
/// StmtKind::Expr(<body>);
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
@ -1331,136 +1337,75 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body: &Block,
|
||||
opt_label: Option<Label>,
|
||||
) -> hir::Expr<'hir> {
|
||||
let orig_head_span = head.span;
|
||||
// expand <head>
|
||||
let mut head = self.lower_expr_mut(head);
|
||||
let desugared_span = self.mark_span_with_reason(
|
||||
DesugaringKind::ForLoop(ForLoopLoc::Head),
|
||||
orig_head_span,
|
||||
None,
|
||||
);
|
||||
head.span = self.lower_span(desugared_span);
|
||||
let head = self.lower_expr_mut(head);
|
||||
let pat = self.lower_pat(pat);
|
||||
let for_span =
|
||||
self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
|
||||
let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
|
||||
let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
|
||||
|
||||
let iter = Ident::with_dummy_span(sym::iter);
|
||||
|
||||
let next_ident = Ident::with_dummy_span(sym::__next);
|
||||
let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
|
||||
desugared_span,
|
||||
next_ident,
|
||||
hir::BindingAnnotation::Mutable,
|
||||
);
|
||||
|
||||
// `::std::option::Option::Some(val) => __next = val`
|
||||
let pat_arm = {
|
||||
let val_ident = Ident::with_dummy_span(sym::val);
|
||||
let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
|
||||
let val_expr = self.expr_ident(pat.span, val_ident, val_pat_hid);
|
||||
let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid);
|
||||
let assign = self.arena.alloc(self.expr(
|
||||
pat.span,
|
||||
hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)),
|
||||
ThinVec::new(),
|
||||
));
|
||||
let some_pat = self.pat_some(pat.span, val_pat);
|
||||
self.arm(some_pat, assign)
|
||||
};
|
||||
|
||||
// `::std::option::Option::None => break`
|
||||
let break_arm = {
|
||||
// `None => break`
|
||||
let none_arm = {
|
||||
let break_expr =
|
||||
self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
|
||||
let pat = self.pat_none(e.span);
|
||||
self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new()));
|
||||
let pat = self.pat_none(for_span);
|
||||
self.arm(pat, break_expr)
|
||||
};
|
||||
|
||||
// `mut iter`
|
||||
let (iter_pat, iter_pat_nid) =
|
||||
self.pat_ident_binding_mode(desugared_span, iter, hir::BindingAnnotation::Mutable);
|
||||
// Some(<pat>) => <body>,
|
||||
let some_arm = {
|
||||
let some_pat = self.pat_some(pat_span, pat);
|
||||
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
|
||||
let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new()));
|
||||
self.arm(some_pat, body_expr)
|
||||
};
|
||||
|
||||
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
|
||||
// `mut iter`
|
||||
let iter = Ident::with_dummy_span(sym::iter);
|
||||
let (iter_pat, iter_pat_nid) =
|
||||
self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
|
||||
|
||||
// `match Iterator::next(&mut iter) { ... }`
|
||||
let match_expr = {
|
||||
let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
|
||||
let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
|
||||
let iter = self.expr_ident(head_span, iter, iter_pat_nid);
|
||||
let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
|
||||
let next_expr = self.expr_call_lang_item_fn(
|
||||
desugared_span,
|
||||
head_span,
|
||||
hir::LangItem::IteratorNext,
|
||||
arena_vec![self; ref_mut_iter],
|
||||
);
|
||||
let arms = arena_vec![self; pat_arm, break_arm];
|
||||
let arms = arena_vec![self; none_arm, some_arm];
|
||||
|
||||
self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
|
||||
self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
|
||||
};
|
||||
let match_stmt = self.stmt_expr(desugared_span, match_expr);
|
||||
let match_stmt = self.stmt_expr(for_span, match_expr);
|
||||
|
||||
let next_expr = self.expr_ident(desugared_span, next_ident, next_pat_hid);
|
||||
|
||||
// `let mut __next`
|
||||
let next_let = self.stmt_let_pat(
|
||||
None,
|
||||
desugared_span,
|
||||
None,
|
||||
next_pat,
|
||||
hir::LocalSource::ForLoopDesugar,
|
||||
);
|
||||
|
||||
// `let <pat> = __next`
|
||||
let pat = self.lower_pat(pat);
|
||||
let pat_let = self.stmt_let_pat(
|
||||
None,
|
||||
desugared_span,
|
||||
Some(next_expr),
|
||||
pat,
|
||||
hir::LocalSource::ForLoopDesugar,
|
||||
);
|
||||
|
||||
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
|
||||
let body_expr = self.expr_block(body_block, ThinVec::new());
|
||||
let body_stmt = self.stmt_expr(body.span, body_expr);
|
||||
|
||||
let loop_block = self.block_all(
|
||||
e.span,
|
||||
arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
|
||||
None,
|
||||
);
|
||||
let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);
|
||||
|
||||
// `[opt_ident]: loop { ... }`
|
||||
let kind = hir::ExprKind::Loop(
|
||||
loop_block,
|
||||
self.lower_label(opt_label),
|
||||
hir::LoopSource::ForLoop,
|
||||
self.lower_span(e.span.with_hi(orig_head_span.hi())),
|
||||
self.lower_span(for_span.with_hi(head.span.hi())),
|
||||
);
|
||||
let loop_expr = self.arena.alloc(hir::Expr {
|
||||
hir_id: self.lower_node_id(e.id),
|
||||
kind,
|
||||
span: self.lower_span(e.span),
|
||||
});
|
||||
let loop_expr =
|
||||
self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span });
|
||||
|
||||
// `mut iter => { ... }`
|
||||
let iter_arm = self.arm(iter_pat, loop_expr);
|
||||
|
||||
let into_iter_span = self.mark_span_with_reason(
|
||||
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
|
||||
orig_head_span,
|
||||
None,
|
||||
);
|
||||
|
||||
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
||||
let into_iter_expr = {
|
||||
self.expr_call_lang_item_fn(
|
||||
into_iter_span,
|
||||
head_span,
|
||||
hir::LangItem::IntoIterIntoIter,
|
||||
arena_vec![self; head],
|
||||
)
|
||||
};
|
||||
|
||||
// #82462: to correctly diagnose borrow errors, the block that contains
|
||||
// the iter expr needs to have a span that covers the loop body.
|
||||
let desugared_full_span =
|
||||
self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
|
||||
|
||||
let match_expr = self.arena.alloc(self.expr_match(
|
||||
desugared_full_span,
|
||||
for_span,
|
||||
into_iter_expr,
|
||||
arena_vec![self; iter_arm],
|
||||
hir::MatchSource::ForLoopDesugar,
|
||||
@ -1474,7 +1419,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// surrounding scope of the `match` since the `match` is not a terminating scope.
|
||||
//
|
||||
// Also, add the attributes to the outer returned expr node.
|
||||
self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into())
|
||||
self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
|
||||
}
|
||||
|
||||
/// Desugar `ExprKind::Try` from: `<expr>?` into:
|
||||
|
||||
@ -1,187 +1,107 @@
|
||||
use crate::arena::Arena;
|
||||
use crate::hir::map::Map;
|
||||
use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_hir::definitions;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::*;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::iter::repeat;
|
||||
use tracing::debug;
|
||||
|
||||
/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
|
||||
pub(super) struct NodeCollector<'a, 'hir> {
|
||||
arena: &'hir Arena<'hir>,
|
||||
|
||||
/// The crate
|
||||
krate: &'hir Crate<'hir>,
|
||||
|
||||
/// Source map
|
||||
source_map: &'a SourceMap,
|
||||
bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
|
||||
|
||||
map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
|
||||
parenting: FxHashMap<LocalDefId, HirId>,
|
||||
/// Outputs
|
||||
nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
|
||||
parenting: FxHashMap<LocalDefId, ItemLocalId>,
|
||||
|
||||
/// The parent of this node
|
||||
parent_node: hir::HirId,
|
||||
parent_node: hir::ItemLocalId,
|
||||
|
||||
current_dep_node_owner: LocalDefId,
|
||||
owner: LocalDefId,
|
||||
|
||||
definitions: &'a definitions::Definitions,
|
||||
|
||||
hcx: StableHashingContext<'a>,
|
||||
}
|
||||
|
||||
fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
|
||||
let i = k.index();
|
||||
let len = map.len();
|
||||
if i >= len {
|
||||
map.extend(repeat(None).take(i - len + 1));
|
||||
}
|
||||
debug_assert!(map[k].is_none());
|
||||
map[k] = Some(v);
|
||||
}
|
||||
pub(super) fn index_hir<'hir>(
|
||||
sess: &Session,
|
||||
definitions: &definitions::Definitions,
|
||||
item: hir::OwnerNode<'hir>,
|
||||
bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
|
||||
) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
|
||||
let mut nodes = IndexVec::new();
|
||||
// This node's parent should never be accessed: the owner's parent is computed by the
|
||||
// hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
|
||||
// used.
|
||||
nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
|
||||
let mut collector = NodeCollector {
|
||||
source_map: sess.source_map(),
|
||||
definitions,
|
||||
owner: item.def_id(),
|
||||
parent_node: ItemLocalId::new(0),
|
||||
nodes,
|
||||
bodies,
|
||||
parenting: FxHashMap::default(),
|
||||
};
|
||||
|
||||
fn hash_body(
|
||||
hcx: &mut StableHashingContext<'_>,
|
||||
item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
|
||||
) -> Fingerprint {
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
hcx.while_hashing_hir_bodies(true, |hcx| {
|
||||
item_like.hash_stable(hcx, &mut stable_hasher);
|
||||
});
|
||||
stable_hasher.finish()
|
||||
match item {
|
||||
OwnerNode::Crate(citem) => collector.visit_mod(&citem, citem.inner, hir::CRATE_HIR_ID),
|
||||
OwnerNode::Item(item) => collector.visit_item(item),
|
||||
OwnerNode::TraitItem(item) => collector.visit_trait_item(item),
|
||||
OwnerNode::ImplItem(item) => collector.visit_impl_item(item),
|
||||
OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item),
|
||||
};
|
||||
|
||||
(collector.nodes, collector.parenting)
|
||||
}
|
||||
|
||||
impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
||||
pub(super) fn root(
|
||||
sess: &'a Session,
|
||||
arena: &'hir Arena<'hir>,
|
||||
krate: &'hir Crate<'hir>,
|
||||
definitions: &'a definitions::Definitions,
|
||||
hcx: StableHashingContext<'a>,
|
||||
) -> NodeCollector<'a, 'hir> {
|
||||
let mut collector = NodeCollector {
|
||||
arena,
|
||||
krate,
|
||||
source_map: sess.source_map(),
|
||||
parent_node: hir::CRATE_HIR_ID,
|
||||
current_dep_node_owner: CRATE_DEF_ID,
|
||||
definitions,
|
||||
hcx,
|
||||
map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
|
||||
parenting: FxHashMap::default(),
|
||||
};
|
||||
collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module()));
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
|
||||
// Insert bodies into the map
|
||||
for (id, body) in self.krate.bodies.iter() {
|
||||
let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies;
|
||||
assert!(bodies.insert(id.hir_id.local_id, body).is_none());
|
||||
}
|
||||
IndexedHir { map: self.map, parenting: self.parenting }
|
||||
}
|
||||
|
||||
fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) {
|
||||
let hash = hash_body(&mut self.hcx, node);
|
||||
|
||||
let mut nodes = IndexVec::new();
|
||||
nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() }));
|
||||
|
||||
debug_assert!(self.map[owner].is_none());
|
||||
self.map[owner] =
|
||||
Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() }));
|
||||
}
|
||||
|
||||
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
|
||||
debug_assert_eq!(self.current_dep_node_owner, hir_id.owner);
|
||||
debug_assert_eq!(self.owner, hir_id.owner);
|
||||
debug_assert_ne!(hir_id.local_id.as_u32(), 0);
|
||||
|
||||
// Make sure that the DepNode of some node coincides with the HirId
|
||||
// owner of that node.
|
||||
if cfg!(debug_assertions) {
|
||||
if hir_id.owner != self.current_dep_node_owner {
|
||||
let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
|
||||
Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(),
|
||||
None => format!("{:?}", node),
|
||||
};
|
||||
|
||||
span_bug!(
|
||||
span,
|
||||
"inconsistent DepNode at `{:?}` for `{}`: \
|
||||
if hir_id.owner != self.owner {
|
||||
panic!(
|
||||
"inconsistent DepNode at `{:?}` for `{:?}`: \
|
||||
current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
|
||||
self.source_map.span_to_diagnostic_string(span),
|
||||
node_str,
|
||||
self.definitions
|
||||
.def_path(self.current_dep_node_owner)
|
||||
.to_string_no_crate_verbose(),
|
||||
self.current_dep_node_owner,
|
||||
node,
|
||||
self.definitions.def_path(self.owner).to_string_no_crate_verbose(),
|
||||
self.owner,
|
||||
self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
|
||||
hir_id.owner,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let nodes = self.map[hir_id.owner].as_mut().unwrap();
|
||||
|
||||
debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner);
|
||||
insert_vec_map(
|
||||
&mut nodes.nodes,
|
||||
hir_id.local_id,
|
||||
ParentedNode { parent: self.parent_node.local_id, node: node },
|
||||
);
|
||||
self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node: node });
|
||||
}
|
||||
|
||||
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
|
||||
debug_assert_eq!(parent_node_id.owner, self.owner);
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = parent_node_id;
|
||||
self.parent_node = parent_node_id.local_id;
|
||||
f(self);
|
||||
self.parent_node = parent_node;
|
||||
}
|
||||
|
||||
fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) {
|
||||
let prev_owner = self.current_dep_node_owner;
|
||||
let prev_parent = self.parent_node;
|
||||
|
||||
self.current_dep_node_owner = dep_node_owner;
|
||||
self.parent_node = HirId::make_owner(dep_node_owner);
|
||||
f(self);
|
||||
self.current_dep_node_owner = prev_owner;
|
||||
self.parent_node = prev_parent;
|
||||
}
|
||||
|
||||
fn insert_nested(&mut self, item: LocalDefId) {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let dk_parent = self.definitions.def_key(item).parent.unwrap();
|
||||
let dk_parent = LocalDefId { local_def_index: dk_parent };
|
||||
let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
|
||||
debug_assert_eq!(
|
||||
dk_parent.owner, self.parent_node.owner,
|
||||
"Different parents for {:?}",
|
||||
item
|
||||
)
|
||||
}
|
||||
|
||||
assert_eq!(self.parenting.insert(item, self.parent_node), None);
|
||||
self.parenting.insert(item, self.parent_node);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
type Map = Map<'hir>;
|
||||
type Map = !;
|
||||
|
||||
/// Because we want to track parent items and so forth, enable
|
||||
/// deep walking so that we walk nested items in the context of
|
||||
@ -194,26 +114,24 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
fn visit_nested_item(&mut self, item: ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item);
|
||||
self.insert_nested(item.def_id);
|
||||
self.visit_item(self.krate.item(item));
|
||||
}
|
||||
|
||||
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
|
||||
self.insert_nested(item_id.def_id);
|
||||
self.visit_trait_item(self.krate.trait_item(item_id));
|
||||
}
|
||||
|
||||
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
|
||||
self.insert_nested(item_id.def_id);
|
||||
self.visit_impl_item(self.krate.impl_item(item_id));
|
||||
}
|
||||
|
||||
fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
|
||||
self.insert_nested(foreign_id.def_id);
|
||||
self.visit_foreign_item(self.krate.foreign_item(foreign_id));
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, id: BodyId) {
|
||||
self.visit_body(self.krate.body(id));
|
||||
debug_assert_eq!(id.hir_id.owner, self.owner);
|
||||
let body = self.bodies[&id.hir_id.local_id];
|
||||
self.visit_body(body);
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'hir Param<'hir>) {
|
||||
@ -226,8 +144,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
|
||||
fn visit_item(&mut self, i: &'hir Item<'hir>) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
self.insert_owner(i.def_id, OwnerNode::Item(i));
|
||||
self.with_dep_node_owner(i.def_id, |this| {
|
||||
debug_assert_eq!(i.def_id, self.owner);
|
||||
self.with_parent(i.hir_id(), |this| {
|
||||
if let ItemKind::Struct(ref struct_def, _) = i.kind {
|
||||
// If this is a tuple or unit-like struct, register the constructor.
|
||||
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
|
||||
@ -239,8 +157,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
|
||||
self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi));
|
||||
self.with_dep_node_owner(fi.def_id, |this| {
|
||||
debug_assert_eq!(fi.def_id, self.owner);
|
||||
self.with_parent(fi.hir_id(), |this| {
|
||||
intravisit::walk_foreign_item(this, fi);
|
||||
});
|
||||
}
|
||||
@ -257,15 +175,15 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
|
||||
self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti));
|
||||
self.with_dep_node_owner(ti.def_id, |this| {
|
||||
debug_assert_eq!(ti.def_id, self.owner);
|
||||
self.with_parent(ti.hir_id(), |this| {
|
||||
intravisit::walk_trait_item(this, ti);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
|
||||
self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii));
|
||||
self.with_dep_node_owner(ii.def_id, |this| {
|
||||
debug_assert_eq!(ii.def_id, self.owner);
|
||||
self.with_parent(ii.hir_id(), |this| {
|
||||
intravisit::walk_impl_item(this, ii);
|
||||
});
|
||||
}
|
||||
@ -353,7 +271,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
s: Span,
|
||||
id: HirId,
|
||||
) {
|
||||
assert_eq!(self.parent_node, id);
|
||||
assert_eq!(self.owner, id.owner);
|
||||
assert_eq!(self.parent_node, id.local_id);
|
||||
intravisit::walk_fn(self, fk, fd, b, s, id);
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_span::source_map::{respan, DesugaringKind};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
@ -39,6 +40,11 @@ impl ItemLowerer<'_, '_, '_> {
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
|
||||
fn visit_attribute(&mut self, _: &'a Attribute) {
|
||||
// We do not want to lower expressions that appear in attributes,
|
||||
// as they are not accessible to the rest of the HIR.
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'a Item) {
|
||||
let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
|
||||
@ -48,7 +54,7 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
|
||||
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
|
||||
let this = &mut ItemLowerer { lctx: this };
|
||||
match item.kind {
|
||||
ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
|
||||
ItemKind::Impl(box Impl { ref of_trait, .. }) => {
|
||||
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
|
||||
}
|
||||
_ => visit::walk_item(this, item),
|
||||
@ -99,11 +105,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
) -> T {
|
||||
let old_len = self.in_scope_lifetimes.len();
|
||||
|
||||
let parent_generics = match self.owners[parent_hir_id].unwrap().expect_item().kind {
|
||||
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
|
||||
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
|
||||
_ => &[],
|
||||
};
|
||||
let parent_generics =
|
||||
match self.owners[parent_hir_id].as_ref().unwrap().node().expect_item().kind {
|
||||
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
|
||||
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
|
||||
_ => &[],
|
||||
};
|
||||
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()),
|
||||
_ => None,
|
||||
@ -216,12 +223,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
|
||||
hir::ItemKind::Const(ty, body_id)
|
||||
}
|
||||
ItemKind::Fn(box FnKind(
|
||||
_,
|
||||
FnSig { ref decl, header, span: fn_sig_span },
|
||||
ItemKind::Fn(box Fn {
|
||||
sig: FnSig { ref decl, header, span: fn_sig_span },
|
||||
ref generics,
|
||||
ref body,
|
||||
)) => {
|
||||
..
|
||||
}) => {
|
||||
let fn_def_id = self.resolver.local_def_id(id);
|
||||
self.with_new_scopes(|this| {
|
||||
this.current_item = Some(ident.span);
|
||||
@ -271,7 +278,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ItemKind::GlobalAsm(ref asm) => {
|
||||
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
|
||||
}
|
||||
ItemKind::TyAlias(box TyAliasKind(_, ref gen, _, Some(ref ty))) => {
|
||||
ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => {
|
||||
// We lower
|
||||
//
|
||||
// type Foo = impl Trait
|
||||
@ -286,10 +293,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
},
|
||||
);
|
||||
let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
}
|
||||
ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, None)) => {
|
||||
ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
|
||||
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
@ -316,7 +323,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
)
|
||||
}
|
||||
ItemKind::Impl(box ImplKind {
|
||||
ItemKind::Impl(box Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
@ -382,13 +389,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
items: new_impl_items,
|
||||
})
|
||||
}
|
||||
ItemKind::Trait(box TraitKind(
|
||||
ItemKind::Trait(box Trait {
|
||||
is_auto,
|
||||
unsafety,
|
||||
ref generics,
|
||||
ref bounds,
|
||||
ref items,
|
||||
)) => {
|
||||
}) => {
|
||||
let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
|
||||
let items = self
|
||||
.arena
|
||||
@ -493,7 +500,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
|
||||
let vis = this.rebuild_vis(&vis);
|
||||
if let Some(attrs) = attrs {
|
||||
this.attrs.insert(hir::HirId::make_owner(new_id), attrs);
|
||||
this.attrs.insert(hir::ItemLocalId::new(0), attrs);
|
||||
}
|
||||
|
||||
let item = hir::Item {
|
||||
@ -568,7 +575,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let kind =
|
||||
this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
|
||||
if let Some(attrs) = attrs {
|
||||
this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs);
|
||||
this.attrs.insert(hir::ItemLocalId::new(0), attrs);
|
||||
}
|
||||
|
||||
let item = hir::Item {
|
||||
@ -653,7 +660,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
def_id,
|
||||
ident: self.lower_ident(i.ident),
|
||||
kind: match i.kind {
|
||||
ForeignItemKind::Fn(box FnKind(_, ref sig, ref generics, _)) => {
|
||||
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
|
||||
let fdec = &sig.decl;
|
||||
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
|
||||
generics,
|
||||
@ -770,13 +777,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
|
||||
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, None)) => {
|
||||
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
|
||||
let names = self.lower_fn_params_to_names(&sig.decl);
|
||||
let (generics, sig) =
|
||||
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, Some(ref body))) => {
|
||||
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
|
||||
let asyncness = sig.header.asyncness;
|
||||
let body_id =
|
||||
self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
|
||||
@ -789,8 +796,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref default)) => {
|
||||
let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
|
||||
AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
|
||||
let ty = ty.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
let kind = hir::TraitItemKind::Type(
|
||||
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
|
||||
@ -816,11 +823,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
|
||||
let (kind, has_default) = match &i.kind {
|
||||
AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
|
||||
AssocItemKind::TyAlias(box TyAliasKind(_, _, _, default)) => {
|
||||
(hir::AssocItemKind::Type, default.is_some())
|
||||
AssocItemKind::TyAlias(box TyAlias { ty, .. }) => {
|
||||
(hir::AssocItemKind::Type, ty.is_some())
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, sig, _, default)) => {
|
||||
(hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, default.is_some())
|
||||
AssocItemKind::Fn(box Fn { sig, body, .. }) => {
|
||||
(hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, body.is_some())
|
||||
}
|
||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
||||
};
|
||||
@ -851,7 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
|
||||
)
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
|
||||
self.current_item = Some(i.span);
|
||||
let asyncness = sig.header.asyncness;
|
||||
let body_id =
|
||||
@ -867,7 +874,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, ty)) => {
|
||||
AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
let kind = match ty {
|
||||
None => {
|
||||
@ -918,7 +925,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
kind: match &i.kind {
|
||||
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
|
||||
AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
|
||||
AssocItemKind::Fn(box FnKind(_, sig, ..)) => {
|
||||
AssocItemKind::Fn(box Fn { sig, .. }) => {
|
||||
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
|
||||
}
|
||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
||||
@ -971,7 +978,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
) -> hir::BodyId {
|
||||
let body = hir::Body { generator_kind: self.generator_kind, params, value };
|
||||
let id = body.id();
|
||||
self.bodies.insert(id, body);
|
||||
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
||||
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
|
||||
id
|
||||
}
|
||||
|
||||
@ -1124,7 +1132,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
//
|
||||
// If this is the simple case, this parameter will end up being the same as the
|
||||
// original parameter, but with a different pattern id.
|
||||
let stmt_attrs = this.attrs.get(¶meter.hir_id).copied();
|
||||
let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied();
|
||||
let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
|
||||
let new_parameter = hir::Param {
|
||||
hir_id: parameter.hir_id,
|
||||
|
||||
@ -33,16 +33,19 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::token::{self, Token};
|
||||
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
|
||||
use rustc_ast::visit;
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
@ -52,18 +55,18 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
||||
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind};
|
||||
use rustc_span::source_map::{respan, DesugaringKind};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::BTreeMap;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
macro_rules! arena_vec {
|
||||
@ -76,11 +79,12 @@ macro_rules! arena_vec {
|
||||
mod asm;
|
||||
mod block;
|
||||
mod expr;
|
||||
mod index;
|
||||
mod item;
|
||||
mod pat;
|
||||
mod path;
|
||||
|
||||
rustc_hir::arena_types!(rustc_arena::declare_arena, 'tcx);
|
||||
rustc_hir::arena_types!(rustc_arena::declare_arena);
|
||||
|
||||
struct LoweringContext<'a, 'hir: 'a> {
|
||||
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
|
||||
@ -97,13 +101,14 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||
arena: &'hir Arena<'hir>,
|
||||
|
||||
/// The items being lowered are collected here.
|
||||
owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
|
||||
bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
|
||||
owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>,
|
||||
/// Bodies inside the owner being lowered.
|
||||
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
|
||||
/// Attributes inside the owner being lowered.
|
||||
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
|
||||
|
||||
generator_kind: Option<hir::GeneratorKind>,
|
||||
|
||||
attrs: BTreeMap<hir::HirId, &'hir [Attribute]>,
|
||||
|
||||
/// When inside an `async` context, this is the `HirId` of the
|
||||
/// `task_context` local bound to the resume argument of the generator.
|
||||
task_context: Option<hir::HirId>,
|
||||
@ -152,6 +157,9 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
|
||||
|
||||
/// NodeIds that are lowered inside the current HIR owner.
|
||||
local_node_ids: Vec<NodeId>,
|
||||
|
||||
allow_try_trait: Option<Lrc<[Symbol]>>,
|
||||
allow_gen_future: Option<Lrc<[Symbol]>>,
|
||||
}
|
||||
@ -178,11 +186,13 @@ pub trait ResolverAstLowering {
|
||||
/// This should only return `None` during testing.
|
||||
fn definitions(&mut self) -> &mut Definitions;
|
||||
|
||||
fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
|
||||
|
||||
fn lint_buffer(&mut self) -> &mut LintBuffer;
|
||||
|
||||
fn next_node_id(&mut self) -> NodeId;
|
||||
|
||||
fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
|
||||
fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<hir::TraitCandidate>>;
|
||||
|
||||
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
|
||||
|
||||
@ -200,37 +210,6 @@ pub trait ResolverAstLowering {
|
||||
) -> LocalDefId;
|
||||
}
|
||||
|
||||
struct LoweringHasher<'a> {
|
||||
source_map: CachingSourceMapView<'a>,
|
||||
resolver: &'a dyn ResolverAstLowering,
|
||||
}
|
||||
|
||||
impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> {
|
||||
#[inline]
|
||||
fn hash_spans(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn def_span(&self, id: LocalDefId) -> Span {
|
||||
self.resolver.def_span(id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
|
||||
self.resolver.def_path_hash(def_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_data_to_lines_and_cols(
|
||||
&mut self,
|
||||
span: &rustc_span::SpanData,
|
||||
) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
|
||||
{
|
||||
self.source_map.span_data_to_lines_and_cols(span)
|
||||
}
|
||||
}
|
||||
|
||||
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
|
||||
/// and if so, what meaning it has.
|
||||
#[derive(Debug)]
|
||||
@ -314,14 +293,15 @@ pub fn lower_crate<'a, 'hir>(
|
||||
) -> &'hir hir::Crate<'hir> {
|
||||
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
|
||||
|
||||
let owners = IndexVec::from_fn_n(|_| None, resolver.definitions().def_index_count());
|
||||
LoweringContext {
|
||||
sess,
|
||||
resolver,
|
||||
nt_to_tokenstream,
|
||||
arena,
|
||||
owners: IndexVec::default(),
|
||||
bodies: BTreeMap::new(),
|
||||
attrs: BTreeMap::default(),
|
||||
owners,
|
||||
bodies: Vec::new(),
|
||||
attrs: SortedMap::new(),
|
||||
catch_scope: None,
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
@ -331,6 +311,7 @@ pub fn lower_crate<'a, 'hir>(
|
||||
current_hir_id_owner: CRATE_DEF_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::new(0),
|
||||
node_id_to_hir_id: IndexVec::new(),
|
||||
local_node_ids: Vec::new(),
|
||||
generator_kind: None,
|
||||
task_context: None,
|
||||
current_item: None,
|
||||
@ -420,13 +401,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir::OwnerNode::Crate(lctx.arena.alloc(module))
|
||||
});
|
||||
|
||||
let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
|
||||
for (k, v) in self.resolver.take_trait_map().into_iter() {
|
||||
if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
|
||||
let map = trait_map.entry(hir_id.owner).or_default();
|
||||
map.insert(hir_id.local_id, v.into_boxed_slice());
|
||||
}
|
||||
}
|
||||
let hir_hash = self.compute_hir_hash();
|
||||
|
||||
let mut def_id_to_hir_id = IndexVec::default();
|
||||
|
||||
@ -441,24 +416,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (&id, attrs) in self.attrs.iter() {
|
||||
// Verify that we do not store empty slices in the map.
|
||||
if attrs.is_empty() {
|
||||
panic!("Stored empty attributes for {:?}", id);
|
||||
}
|
||||
}
|
||||
|
||||
let krate =
|
||||
hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs };
|
||||
let krate = hir::Crate { owners: self.owners, hir_hash };
|
||||
self.arena.alloc(krate)
|
||||
}
|
||||
|
||||
fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
|
||||
LoweringHasher {
|
||||
source_map: CachingSourceMapView::new(self.sess.source_map()),
|
||||
resolver: self.resolver,
|
||||
}
|
||||
/// Compute the hash for the HIR of the full crate.
|
||||
/// This hash will then be part of the crate_hash which is stored in the metadata.
|
||||
fn compute_hir_hash(&mut self) -> Fingerprint {
|
||||
let definitions = self.resolver.definitions();
|
||||
let mut hir_body_nodes: Vec<_> = self
|
||||
.owners
|
||||
.iter_enumerated()
|
||||
.filter_map(|(def_id, info)| {
|
||||
let info = info.as_ref()?;
|
||||
let def_path_hash = definitions.def_path_hash(def_id);
|
||||
Some((def_path_hash, info))
|
||||
})
|
||||
.collect();
|
||||
hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
|
||||
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
let mut hcx = self.resolver.create_stable_hashing_context();
|
||||
hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
stable_hasher.finish()
|
||||
}
|
||||
|
||||
fn with_hir_id_owner(
|
||||
@ -468,25 +448,93 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
) -> LocalDefId {
|
||||
let def_id = self.resolver.local_def_id(owner);
|
||||
|
||||
// Always allocate the first `HirId` for the owner itself.
|
||||
let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
|
||||
debug_assert_eq!(_old, None);
|
||||
|
||||
let current_attrs = std::mem::take(&mut self.attrs);
|
||||
let current_bodies = std::mem::take(&mut self.bodies);
|
||||
let current_node_ids = std::mem::take(&mut self.local_node_ids);
|
||||
let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
|
||||
let current_local_counter =
|
||||
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
|
||||
|
||||
let item = f(self);
|
||||
// Always allocate the first `HirId` for the owner itself.
|
||||
let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
|
||||
debug_assert_eq!(_old, None);
|
||||
self.local_node_ids.push(owner);
|
||||
|
||||
let item = f(self);
|
||||
debug_assert_eq!(def_id, item.def_id());
|
||||
let info = self.make_owner_info(item);
|
||||
|
||||
self.attrs = current_attrs;
|
||||
self.bodies = current_bodies;
|
||||
self.local_node_ids = current_node_ids;
|
||||
self.current_hir_id_owner = current_owner;
|
||||
self.item_local_id_counter = current_local_counter;
|
||||
|
||||
let _old = self.owners.insert(def_id, item);
|
||||
let _old = self.owners.insert(def_id, info);
|
||||
debug_assert!(_old.is_none());
|
||||
|
||||
def_id
|
||||
}
|
||||
|
||||
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
|
||||
let attrs = std::mem::take(&mut self.attrs);
|
||||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
let local_node_ids = std::mem::take(&mut self.local_node_ids);
|
||||
let trait_map = local_node_ids
|
||||
.into_iter()
|
||||
.filter_map(|node_id| {
|
||||
let hir_id = self.node_id_to_hir_id[node_id]?;
|
||||
let traits = self.resolver.take_trait_map(node_id)?;
|
||||
Some((hir_id.local_id, traits.into_boxed_slice()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (id, attrs) in attrs.iter() {
|
||||
// Verify that we do not store empty slices in the map.
|
||||
if attrs.is_empty() {
|
||||
panic!("Stored empty attributes for {:?}", id);
|
||||
}
|
||||
}
|
||||
|
||||
bodies.sort_by_key(|(k, _)| *k);
|
||||
let bodies = SortedMap::from_presorted_elements(bodies);
|
||||
let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
|
||||
let (nodes, parenting) =
|
||||
index::index_hir(self.sess, self.resolver.definitions(), node, &bodies);
|
||||
let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies };
|
||||
let attrs = {
|
||||
let mut hcx = self.resolver.create_stable_hashing_context();
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
attrs.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
let hash = stable_hasher.finish();
|
||||
hir::AttributeMap { map: attrs, hash }
|
||||
};
|
||||
|
||||
hir::OwnerInfo { nodes, parenting, attrs, trait_map }
|
||||
}
|
||||
|
||||
/// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
|
||||
/// queries which depend on the full HIR tree and those which only depend on the item signature.
|
||||
fn hash_owner(
|
||||
&mut self,
|
||||
node: hir::OwnerNode<'hir>,
|
||||
bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
|
||||
) -> (Fingerprint, Fingerprint) {
|
||||
let mut hcx = self.resolver.create_stable_hashing_context();
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
|
||||
node.hash_stable(hcx, &mut stable_hasher)
|
||||
});
|
||||
let hash_including_bodies = stable_hasher.finish();
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| {
|
||||
node.hash_stable(hcx, &mut stable_hasher)
|
||||
});
|
||||
let hash_without_bodies = stable_hasher.finish();
|
||||
(hash_including_bodies, hash_without_bodies)
|
||||
}
|
||||
|
||||
/// This method allocates a new `HirId` for the given `NodeId` and stores it in
|
||||
/// the `LoweringContext`'s `NodeId => HirId` map.
|
||||
/// Take care not to call this method if the resulting `HirId` is then not
|
||||
@ -501,6 +549,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let owner = self.current_hir_id_owner;
|
||||
let local_id = self.item_local_id_counter;
|
||||
self.item_local_id_counter.increment_by(1);
|
||||
self.local_node_ids.push(ast_node_id);
|
||||
hir::HirId { owner, local_id }
|
||||
})
|
||||
}
|
||||
@ -547,7 +596,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
allow_internal_unstable,
|
||||
reason,
|
||||
self.sess.edition(),
|
||||
self.create_stable_hashing_context(),
|
||||
self.resolver.create_stable_hashing_context(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -791,9 +840,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
if attrs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
debug_assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
|
||||
debug_assert!(!ret.is_empty());
|
||||
self.attrs.insert(id, ret);
|
||||
self.attrs.insert(id.local_id, ret);
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
@ -819,9 +869,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) {
|
||||
if let Some(&a) = self.attrs.get(&target_id) {
|
||||
debug_assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
|
||||
if let Some(&a) = self.attrs.get(&target_id.local_id) {
|
||||
debug_assert!(!a.is_empty());
|
||||
self.attrs.insert(id, a);
|
||||
self.attrs.insert(id.local_id, a);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1286,10 +1338,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
pure_wrt_drop: false,
|
||||
bounds: hir_bounds,
|
||||
span: self.lower_span(span),
|
||||
kind: hir::GenericParamKind::Type {
|
||||
default: None,
|
||||
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
|
||||
},
|
||||
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
|
||||
});
|
||||
|
||||
hir::TyKind::Path(hir::QPath::Resolved(
|
||||
@ -1435,7 +1484,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
trace!("registering opaque type with id {:#?}", opaque_ty_id);
|
||||
let opaque_ty_item = hir::Item {
|
||||
def_id: opaque_ty_id,
|
||||
ident: Ident::invalid(),
|
||||
ident: Ident::empty(),
|
||||
kind: opaque_ty_item_kind,
|
||||
vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
|
||||
span: self.lower_span(opaque_ty_span),
|
||||
@ -1902,12 +1951,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
default: default.as_ref().map(|x| {
|
||||
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other))
|
||||
}),
|
||||
synthetic: param
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.has_name(sym::rustc_synthetic))
|
||||
.map(|_| hir::SyntheticTyParamKind::FromAttr)
|
||||
.next(),
|
||||
synthetic: false,
|
||||
};
|
||||
|
||||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
@ -2066,7 +2110,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let hir_id = self.next_id();
|
||||
if let Some(a) = attrs {
|
||||
debug_assert!(!a.is_empty());
|
||||
self.attrs.insert(hir_id, a);
|
||||
self.attrs.insert(hir_id.local_id, a);
|
||||
}
|
||||
let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
|
||||
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
|
||||
|
||||
@ -113,7 +113,7 @@ impl<'a> AstValidator<'a> {
|
||||
if sess.opts.unstable_features.is_nightly_build() {
|
||||
sess.struct_span_err(expr.span, "`let` expressions are not supported here")
|
||||
.note("only supported directly in conditions of `if`- and `while`-expressions")
|
||||
.note("as well as when nested within `&&` and parenthesis in those conditions")
|
||||
.note("as well as when nested within `&&` and parentheses in those conditions")
|
||||
.emit();
|
||||
} else {
|
||||
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
|
||||
@ -1064,7 +1064,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Impl(box ImplKind {
|
||||
ItemKind::Impl(box Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness: _,
|
||||
@ -1111,7 +1111,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
});
|
||||
return; // Avoid visiting again.
|
||||
}
|
||||
ItemKind::Impl(box ImplKind {
|
||||
ItemKind::Impl(box Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
@ -1152,8 +1152,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => {
|
||||
self.check_defaultness(item.span, def);
|
||||
ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
|
||||
self.check_defaultness(item.span, defaultness);
|
||||
|
||||
if body.is_none() {
|
||||
let msg = "free function without a body";
|
||||
@ -1195,19 +1195,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemKind::Trait(box TraitKind(
|
||||
is_auto,
|
||||
_,
|
||||
ref generics,
|
||||
ref bounds,
|
||||
ref trait_items,
|
||||
)) => {
|
||||
ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
|
||||
if is_auto == IsAuto::Yes {
|
||||
// Auto traits cannot have generics, super traits nor contain items.
|
||||
self.deny_generic_params(generics, item.ident.span);
|
||||
self.deny_super_traits(bounds, item.ident.span);
|
||||
self.deny_where_clause(&generics.where_clause, item.ident.span);
|
||||
self.deny_items(trait_items, item.ident.span);
|
||||
self.deny_items(items, item.ident.span);
|
||||
}
|
||||
self.no_questions_in_bounds(bounds, "supertraits", true);
|
||||
|
||||
@ -1217,7 +1211,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_generics(generics);
|
||||
self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
|
||||
walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
|
||||
walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return;
|
||||
}
|
||||
@ -1278,9 +1272,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
let msg = "free static item without body";
|
||||
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
|
||||
}
|
||||
ItemKind::TyAlias(box TyAliasKind(def, _, ref bounds, ref body)) => {
|
||||
self.check_defaultness(item.span, def);
|
||||
if body.is_none() {
|
||||
ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => {
|
||||
self.check_defaultness(item.span, defaultness);
|
||||
if ty.is_none() {
|
||||
let msg = "free type alias without body";
|
||||
self.error_item_without_body(item.span, "type", msg, " = <type>;");
|
||||
}
|
||||
@ -1294,15 +1288,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|
||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
match &fi.kind {
|
||||
ForeignItemKind::Fn(box FnKind(def, sig, _, body)) => {
|
||||
self.check_defaultness(fi.span, *def);
|
||||
ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAliasKind(def, generics, bounds, body)) => {
|
||||
self.check_defaultness(fi.span, *def);
|
||||
self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
|
||||
ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
|
||||
self.check_type_no_bounds(bounds, "`extern` blocks");
|
||||
self.check_foreign_ty_genericless(generics);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
@ -1587,11 +1581,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
AssocItemKind::Const(_, _, body) => {
|
||||
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, _, _, body)) => {
|
||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAliasKind(_, _, bounds, body)) => {
|
||||
self.check_impl_item_provided(item.span, body, "type", " = <type>;");
|
||||
AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
|
||||
self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
|
||||
self.check_type_no_bounds(bounds, "`impl`s");
|
||||
}
|
||||
_ => {}
|
||||
@ -1600,7 +1594,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|
||||
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
|
||||
self.invalid_visibility(&item.vis, None);
|
||||
if let AssocItemKind::Fn(box FnKind(_, sig, _, _)) = &item.kind {
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
|
||||
}
|
||||
@ -1611,7 +1605,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
match item.kind {
|
||||
AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty))
|
||||
AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
|
||||
if ctxt == AssocCtxt::Trait =>
|
||||
{
|
||||
self.visit_vis(&item.vis);
|
||||
@ -1623,7 +1617,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
});
|
||||
walk_list!(self, visit_ty, ty);
|
||||
}
|
||||
AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
|
||||
AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
|
||||
if self.in_const_trait_impl
|
||||
|| ctxt == AssocCtxt::Trait
|
||||
|| matches!(sig.header.constness, Const::Yes(_)) =>
|
||||
|
||||
@ -3,7 +3,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
|
||||
use rustc_ast::{PatKind, RangeEnd, VariantData};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_feature::{Features, GateIssue};
|
||||
use rustc_session::parse::{feature_err, feature_err_issue};
|
||||
use rustc_session::Session;
|
||||
@ -301,11 +301,14 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
|
||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
||||
let attr_info =
|
||||
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
|
||||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
// Check feature gates for built-in attributes.
|
||||
if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
|
||||
gate_feature_fn!(self, has_feature, attr.span, name, descr);
|
||||
if let Some(BuiltinAttribute {
|
||||
gate: AttributeGate::Gated(_, name, descr, has_feature),
|
||||
..
|
||||
}) = attr_info
|
||||
{
|
||||
gate_feature_fn!(self, has_feature, attr.span, *name, descr);
|
||||
}
|
||||
// Check unstable flavors of the `#[doc]` attribute.
|
||||
if attr.has_name(sym::doc) {
|
||||
@ -322,8 +325,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
cfg_hide => doc_cfg_hide
|
||||
masked => doc_masked
|
||||
notable_trait => doc_notable_trait
|
||||
keyword => doc_keyword
|
||||
);
|
||||
|
||||
if nested_meta.has_name(sym::keyword) {
|
||||
let msg = "`#[doc(keyword)]` is meant for internal use only";
|
||||
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,9 +430,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::Impl(box ast::ImplKind {
|
||||
polarity, defaultness, ref of_trait, ..
|
||||
}) => {
|
||||
ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
|
||||
if let ast::ImplPolarity::Negative(span) = polarity {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
@ -441,7 +446,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::Trait(box ast::TraitKind(ast::IsAuto::Yes, ..)) => {
|
||||
ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
auto_traits,
|
||||
@ -459,7 +464,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
gate_feature_post!(&self, decl_macro, i.span, msg);
|
||||
}
|
||||
|
||||
ast::ItemKind::TyAlias(box ast::TyAliasKind(_, _, _, Some(ref ty))) => {
|
||||
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ref ty), .. }) => {
|
||||
self.check_impl_trait(&ty)
|
||||
}
|
||||
|
||||
@ -541,15 +546,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
ast::ExprKind::TryBlock(_) => {
|
||||
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||
}
|
||||
ast::ExprKind::Block(_, opt_label) => {
|
||||
if let Some(label) = opt_label {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
label_break_value,
|
||||
label.ident.span,
|
||||
"labels on blocks are unstable"
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Block(_, Some(label)) => {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
label_break_value,
|
||||
label.ident.span,
|
||||
"labels on blocks are unstable"
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -634,7 +637,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
|
||||
let is_fn = match i.kind {
|
||||
ast::AssocItemKind::Fn(_) => true,
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAliasKind(_, ref generics, _, ref ty)) => {
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => {
|
||||
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
@ -720,6 +723,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
gate_all!(const_trait_impl, "const trait impls are experimental");
|
||||
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
|
||||
gate_all!(inline_const, "inline-const is experimental");
|
||||
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
|
||||
gate_all!(
|
||||
const_generics_defaults,
|
||||
"default values for const generic parameters are experimental"
|
||||
|
||||
@ -1044,15 +1044,27 @@ impl<'a> State<'a> {
|
||||
self.maybe_print_comment(span.lo());
|
||||
self.print_outer_attributes(attrs);
|
||||
match kind {
|
||||
ast::ForeignItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
|
||||
self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
|
||||
ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
}
|
||||
ast::ForeignItemKind::Static(ty, mutbl, body) => {
|
||||
let def = ast::Defaultness::Final;
|
||||
self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
|
||||
}
|
||||
ast::ForeignItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
|
||||
self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
|
||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
generics,
|
||||
bounds,
|
||||
ty,
|
||||
}) => {
|
||||
self.print_associated_type(
|
||||
ident,
|
||||
generics,
|
||||
bounds,
|
||||
ty.as_deref(),
|
||||
vis,
|
||||
*defaultness,
|
||||
);
|
||||
}
|
||||
ast::ForeignItemKind::MacCall(m) => {
|
||||
self.print_mac(m);
|
||||
@ -1156,9 +1168,17 @@ impl<'a> State<'a> {
|
||||
ast::ItemKind::Const(def, ref ty, ref body) => {
|
||||
self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
|
||||
}
|
||||
ast::ItemKind::Fn(box ast::FnKind(def, ref sig, ref gen, ref body)) => {
|
||||
ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
|
||||
let body = body.as_deref();
|
||||
self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
|
||||
self.print_fn_full(
|
||||
sig,
|
||||
item.ident,
|
||||
generics,
|
||||
&item.vis,
|
||||
defaultness,
|
||||
body,
|
||||
&item.attrs,
|
||||
);
|
||||
}
|
||||
ast::ItemKind::Mod(unsafety, ref mod_kind) => {
|
||||
self.head(self.to_string(|s| {
|
||||
@ -1203,9 +1223,21 @@ impl<'a> State<'a> {
|
||||
self.print_inline_asm(asm);
|
||||
self.end();
|
||||
}
|
||||
ast::ItemKind::TyAlias(box ast::TyAliasKind(def, ref generics, ref bounds, ref ty)) => {
|
||||
ast::ItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
ref generics,
|
||||
ref bounds,
|
||||
ref ty,
|
||||
}) => {
|
||||
let ty = ty.as_deref();
|
||||
self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
|
||||
self.print_associated_type(
|
||||
item.ident,
|
||||
generics,
|
||||
bounds,
|
||||
ty,
|
||||
&item.vis,
|
||||
defaultness,
|
||||
);
|
||||
}
|
||||
ast::ItemKind::Enum(ref enum_definition, ref params) => {
|
||||
self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
|
||||
@ -1218,7 +1250,7 @@ impl<'a> State<'a> {
|
||||
self.head(visibility_qualified(&item.vis, "union"));
|
||||
self.print_struct(struct_def, generics, item.ident, item.span, true);
|
||||
}
|
||||
ast::ItemKind::Impl(box ast::ImplKind {
|
||||
ast::ItemKind::Impl(box ast::Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
@ -1261,13 +1293,14 @@ impl<'a> State<'a> {
|
||||
}
|
||||
self.bclose(item.span);
|
||||
}
|
||||
ast::ItemKind::Trait(box ast::TraitKind(
|
||||
ast::ItemKind::Trait(box ast::Trait {
|
||||
is_auto,
|
||||
unsafety,
|
||||
ref generics,
|
||||
ref bounds,
|
||||
ref trait_items,
|
||||
)) => {
|
||||
ref items,
|
||||
..
|
||||
}) => {
|
||||
self.head("");
|
||||
self.print_visibility(&item.vis);
|
||||
self.print_unsafety(unsafety);
|
||||
@ -1290,7 +1323,7 @@ impl<'a> State<'a> {
|
||||
self.s.word(" ");
|
||||
self.bopen();
|
||||
self.print_inner_attributes(&item.attrs);
|
||||
for trait_item in trait_items {
|
||||
for trait_item in items {
|
||||
self.print_assoc_item(trait_item);
|
||||
}
|
||||
self.bclose(item.span);
|
||||
@ -1405,11 +1438,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
crate fn print_record_struct_body(
|
||||
&mut self,
|
||||
fields: &Vec<ast::FieldDef>,
|
||||
span: rustc_span::Span,
|
||||
) {
|
||||
crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
|
||||
self.nbsp();
|
||||
self.bopen();
|
||||
self.hardbreak_if_not_bol();
|
||||
@ -1483,14 +1512,21 @@ impl<'a> State<'a> {
|
||||
self.maybe_print_comment(span.lo());
|
||||
self.print_outer_attributes(attrs);
|
||||
match kind {
|
||||
ast::AssocItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
|
||||
self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
|
||||
ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
}
|
||||
ast::AssocItemKind::Const(def, ty, body) => {
|
||||
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
|
||||
}
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
|
||||
self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
self.print_associated_type(
|
||||
ident,
|
||||
generics,
|
||||
bounds,
|
||||
ty.as_deref(),
|
||||
vis,
|
||||
*defaultness,
|
||||
);
|
||||
}
|
||||
ast::AssocItemKind::MacCall(m) => {
|
||||
self.print_mac(m);
|
||||
@ -1675,7 +1711,7 @@ impl<'a> State<'a> {
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
|
||||
}
|
||||
|
||||
// Does `expr` need parenthesis when printed in a condition position?
|
||||
// Does `expr` need parentheses when printed in a condition position?
|
||||
//
|
||||
// These cases need parens due to the parse error observed in #26461: `if return {}`
|
||||
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
|
||||
@ -2199,8 +2235,8 @@ impl<'a> State<'a> {
|
||||
|
||||
let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
|
||||
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
|
||||
if let Some((abi, _)) = asm.clobber_abi {
|
||||
args.push(AsmArg::ClobberAbi(abi));
|
||||
for (abi, _) in &asm.clobber_abis {
|
||||
args.push(AsmArg::ClobberAbi(*abi));
|
||||
}
|
||||
if !asm.options.is_empty() {
|
||||
args.push(AsmArg::Options(asm.options));
|
||||
|
||||
@ -12,22 +12,22 @@ use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use std::fmt;
|
||||
use std::ops::Index;
|
||||
|
||||
crate struct BorrowSet<'tcx> {
|
||||
pub struct BorrowSet<'tcx> {
|
||||
/// The fundamental map relating bitvector indexes to the borrows
|
||||
/// in the MIR. Each borrow is also uniquely identified in the MIR
|
||||
/// by the `Location` of the assignment statement in which it
|
||||
/// appears on the right hand side. Thus the location is the map
|
||||
/// key, and its position in the map corresponds to `BorrowIndex`.
|
||||
crate location_map: FxIndexMap<Location, BorrowData<'tcx>>,
|
||||
pub location_map: FxIndexMap<Location, BorrowData<'tcx>>,
|
||||
|
||||
/// Locations which activate borrows.
|
||||
/// NOTE: a given location may activate more than one borrow in the future
|
||||
/// when more general two-phase borrow support is introduced, but for now we
|
||||
/// only need to store one borrow index.
|
||||
crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
|
||||
pub activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
|
||||
|
||||
/// Map from local to all the borrows on that local.
|
||||
crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
|
||||
pub local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
|
||||
|
||||
crate locals_state_at_exit: LocalsStateAtExit,
|
||||
}
|
||||
@ -43,27 +43,27 @@ impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
|
||||
/// Location where a two-phase borrow is activated, if a borrow
|
||||
/// is in fact a two-phase borrow.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
crate enum TwoPhaseActivation {
|
||||
pub enum TwoPhaseActivation {
|
||||
NotTwoPhase,
|
||||
NotActivated,
|
||||
ActivatedAt(Location),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
crate struct BorrowData<'tcx> {
|
||||
pub struct BorrowData<'tcx> {
|
||||
/// Location where the borrow reservation starts.
|
||||
/// In many cases, this will be equal to the activation location but not always.
|
||||
crate reserve_location: Location,
|
||||
pub reserve_location: Location,
|
||||
/// Location where the borrow is activated.
|
||||
crate activation_location: TwoPhaseActivation,
|
||||
pub activation_location: TwoPhaseActivation,
|
||||
/// What kind of borrow this is
|
||||
crate kind: mir::BorrowKind,
|
||||
pub kind: mir::BorrowKind,
|
||||
/// The region for which this borrow is live
|
||||
crate region: RegionVid,
|
||||
pub region: RegionVid,
|
||||
/// Place from which we are borrowing
|
||||
crate borrowed_place: mir::Place<'tcx>,
|
||||
pub borrowed_place: mir::Place<'tcx>,
|
||||
/// Place to which the borrow was stored
|
||||
crate assigned_place: mir::Place<'tcx>,
|
||||
pub assigned_place: mir::Place<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
||||
@ -78,7 +78,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
crate enum LocalsStateAtExit {
|
||||
pub enum LocalsStateAtExit {
|
||||
AllAreInvalidated,
|
||||
SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> },
|
||||
}
|
||||
@ -315,9 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
|
||||
// TEMP = &foo
|
||||
//
|
||||
// so extract `temp`.
|
||||
let temp = if let Some(temp) = assigned_place.as_local() {
|
||||
temp
|
||||
} else {
|
||||
let Some(temp) = assigned_place.as_local() else {
|
||||
span_bug!(
|
||||
self.body.source_info(start_location).span,
|
||||
"expected 2-phase borrow to assign to a local, not `{:?}`",
|
||||
|
||||
@ -339,7 +339,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
// We generally shouldn't have errors here because the query was
|
||||
// already run, but there's no point using `delay_span_bug`
|
||||
// when we're going to emit an error here anyway.
|
||||
let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
|
||||
let _errors = fulfill_cx.select_all_or_error(infcx);
|
||||
|
||||
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
|
||||
debug!("{:#?}", region_constraints);
|
||||
|
||||
@ -11,7 +11,6 @@ use rustc_middle::mir::{
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
|
||||
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
@ -247,6 +246,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
let sess = self.infcx.tcx.sess;
|
||||
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
|
||||
// If we have a `&mut` ref, we need to reborrow.
|
||||
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
|
||||
// If we are in a loop this will be suggested later.
|
||||
if !is_loop_move {
|
||||
err.span_suggestion_verbose(
|
||||
move_span.shrink_to_lo(),
|
||||
&format!(
|
||||
"consider creating a fresh reborrow of {} here",
|
||||
self.describe_place(moved_place.as_ref())
|
||||
.map(|n| format!("`{}`", n))
|
||||
.unwrap_or_else(
|
||||
|| "the mutable reference".to_string()
|
||||
),
|
||||
),
|
||||
"&mut *".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
} else if let Ok(snippet) =
|
||||
sess.source_map().span_to_snippet(move_span)
|
||||
{
|
||||
err.span_suggestion(
|
||||
move_span,
|
||||
"consider borrowing to avoid moving into the for loop",
|
||||
format!("&{}", snippet),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
@ -315,35 +344,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
in_pattern = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
|
||||
let sess = self.infcx.tcx.sess;
|
||||
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
|
||||
// If we have a `&mut` ref, we need to reborrow.
|
||||
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
|
||||
// If we are in a loop this will be suggested later.
|
||||
if !is_loop_move {
|
||||
err.span_suggestion_verbose(
|
||||
move_span.shrink_to_lo(),
|
||||
&format!(
|
||||
"consider creating a fresh reborrow of {} here",
|
||||
self.describe_place(moved_place.as_ref())
|
||||
.map(|n| format!("`{}`", n))
|
||||
.unwrap_or_else(|| "the mutable reference".to_string()),
|
||||
),
|
||||
"&mut *".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
} else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
|
||||
err.span_suggestion(
|
||||
move_span,
|
||||
"consider borrowing to avoid moving into the for loop",
|
||||
format!("&{}", snippet),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use_spans.var_span_label_path_only(
|
||||
@ -408,7 +408,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let param = generics.type_param(¶m_ty, tcx);
|
||||
if let Some(generics) = tcx
|
||||
.hir()
|
||||
.get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
|
||||
.get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
|
||||
{
|
||||
suggest_constraining_type_param(
|
||||
tcx,
|
||||
|
||||
@ -13,7 +13,7 @@ use rustc_middle::mir::{
|
||||
use rustc_middle::ty::adjustment::PointerCast;
|
||||
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{sym, DesugaringKind, Span};
|
||||
|
||||
use crate::region_infer::BlameConstraint;
|
||||
use crate::{
|
||||
@ -53,10 +53,7 @@ pub(crate) enum LaterUseKind {
|
||||
|
||||
impl BorrowExplanation {
|
||||
pub(crate) fn is_explained(&self) -> bool {
|
||||
match self {
|
||||
BorrowExplanation::Unexplained => false,
|
||||
_ => true,
|
||||
}
|
||||
!matches!(self, BorrowExplanation::Unexplained)
|
||||
}
|
||||
pub(crate) fn add_explanation_to_diagnostic<'tcx>(
|
||||
&self,
|
||||
@ -138,7 +135,16 @@ impl BorrowExplanation {
|
||||
should_note_order,
|
||||
} => {
|
||||
let local_decl = &body.local_decls[dropped_local];
|
||||
let (dtor_desc, type_desc) = match local_decl.ty.kind() {
|
||||
let mut ty = local_decl.ty;
|
||||
if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
|
||||
if let ty::Adt(adt, substs) = local_decl.ty.kind() {
|
||||
if tcx.is_diagnostic_item(sym::Option, adt.did) {
|
||||
// in for loop desugaring, only look at the `Some(..)` inner type
|
||||
ty = substs.type_at(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
let (dtor_desc, type_desc) = match ty.kind() {
|
||||
// If type is an ADT that implements Drop, then
|
||||
// simplify output by reporting just the ADT name.
|
||||
ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => {
|
||||
|
||||
@ -13,11 +13,7 @@ use rustc_middle::mir::{
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
|
||||
use rustc_span::{
|
||||
hygiene::{DesugaringKind, ForLoopLoc},
|
||||
symbol::sym,
|
||||
Span,
|
||||
};
|
||||
use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
use super::borrow_set::BorrowData;
|
||||
@ -955,10 +951,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let kind = kind.unwrap_or_else(|| {
|
||||
// This isn't a 'special' use of `self`
|
||||
debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
|
||||
let implicit_into_iter = matches!(
|
||||
fn_call_span.desugaring_kind(),
|
||||
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
|
||||
);
|
||||
let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
|
||||
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
|
||||
let parent_self_ty = parent
|
||||
.filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
|
||||
.and_then(|did| match tcx.type_of(did).kind() {
|
||||
|
||||
@ -5,11 +5,10 @@ use rustc_middle::ty;
|
||||
use rustc_mir_dataflow::move_paths::{
|
||||
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
|
||||
};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::{sym, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
|
||||
|
||||
use crate::diagnostics::UseSpans;
|
||||
use crate::diagnostics::{FnSelfUseKind, UseSpans};
|
||||
use crate::prefixes::PrefixSet;
|
||||
use crate::MirBorrowckCtxt;
|
||||
|
||||
@ -400,19 +399,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
| ty::Opaque(def_id, _) => def_id,
|
||||
_ => return err,
|
||||
};
|
||||
let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id);
|
||||
let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id);
|
||||
if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
|
||||
let diag_name = self.infcx.tcx.get_diagnostic_name(def_id);
|
||||
if matches!(diag_name, Some(sym::Option | sym::Result))
|
||||
&& use_spans.map_or(true, |v| !v.for_closure())
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
&format!(
|
||||
"consider borrowing the `{}`'s content",
|
||||
if is_option { "Option" } else { "Result" }
|
||||
),
|
||||
&format!("consider borrowing the `{}`'s content", diag_name.unwrap()),
|
||||
".as_ref()".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
|
||||
} else if let Some(UseSpans::FnSelfUse {
|
||||
kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
|
||||
..
|
||||
}) = use_spans
|
||||
{
|
||||
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
|
||||
Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
|
||||
type_known_to_meet_bound_modulo_regions(
|
||||
|
||||
@ -45,12 +45,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let item_msg;
|
||||
let reason;
|
||||
let mut opt_source = None;
|
||||
let access_place_desc = self.describe_place(access_place.as_ref());
|
||||
let access_place_desc = self.describe_any_place(access_place.as_ref());
|
||||
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
|
||||
|
||||
match the_place_err {
|
||||
PlaceRef { local, projection: [] } => {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
item_msg = access_place_desc;
|
||||
if access_place.as_local().is_some() {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
@ -83,7 +83,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// If we deref an immutable ref then the suggestion here doesn't help.
|
||||
return;
|
||||
} else {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
item_msg = access_place_desc;
|
||||
if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
@ -96,17 +96,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
PlaceRef { local, projection: [ProjectionElem::Deref] }
|
||||
if self.body.local_decls[local].is_ref_for_guard() =>
|
||||
{
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
item_msg = access_place_desc;
|
||||
reason = ", as it is immutable for the pattern guard".to_string();
|
||||
}
|
||||
PlaceRef { local, projection: [ProjectionElem::Deref] }
|
||||
if self.body.local_decls[local].is_ref_to_static() =>
|
||||
{
|
||||
if access_place.projection.len() == 1 {
|
||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||
item_msg = format!("immutable static item {}", access_place_desc);
|
||||
reason = String::new();
|
||||
} else {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
item_msg = access_place_desc;
|
||||
let local_info = &self.body.local_decls[local].local_info;
|
||||
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
|
||||
let static_name = &self.infcx.tcx.item_name(def_id);
|
||||
@ -121,7 +121,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
&& proj_base.is_empty()
|
||||
&& !self.upvars.is_empty()
|
||||
{
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
item_msg = access_place_desc;
|
||||
debug_assert!(
|
||||
self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
|
||||
);
|
||||
@ -147,7 +147,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
});
|
||||
let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
|
||||
opt_source = Some(source);
|
||||
if let Some(desc) = access_place_desc {
|
||||
if let Some(desc) = self.describe_place(access_place.as_ref()) {
|
||||
item_msg = format!("`{}`", desc);
|
||||
reason = match error_access {
|
||||
AccessKind::Mutate => format!(", which is behind {}", pointer_type),
|
||||
@ -445,15 +445,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
},
|
||||
))) => {
|
||||
// check if the RHS is from desugaring
|
||||
let locations = self.body.find_assignments(local);
|
||||
let opt_assignment_rhs_span = locations
|
||||
.first()
|
||||
.map(|&location| self.body.source_info(location).span);
|
||||
let opt_desugaring_kind =
|
||||
opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
|
||||
match opt_desugaring_kind {
|
||||
let opt_assignment_rhs_span =
|
||||
self.body.find_assignments(local).first().map(|&location| {
|
||||
if let Some(mir::Statement {
|
||||
source_info: _,
|
||||
kind:
|
||||
mir::StatementKind::Assign(box (
|
||||
_,
|
||||
mir::Rvalue::Use(mir::Operand::Copy(place)),
|
||||
)),
|
||||
}) = self.body[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
{
|
||||
self.body.local_decls[place.local].source_info.span
|
||||
} else {
|
||||
self.body.source_info(location).span
|
||||
}
|
||||
});
|
||||
match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
|
||||
// on for loops, RHS points to the iterator part
|
||||
Some(DesugaringKind::ForLoop(_)) => {
|
||||
Some(DesugaringKind::ForLoop) => {
|
||||
self.suggest_similar_mut_method_for_for_loop(&mut err);
|
||||
Some((
|
||||
false,
|
||||
|
||||
@ -90,9 +90,7 @@ impl OutlivesSuggestionBuilder {
|
||||
let mut unified_already = FxHashSet::default();
|
||||
|
||||
for (fr, outlived) in &self.constraints_to_add {
|
||||
let fr_name = if let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) {
|
||||
fr_name
|
||||
} else {
|
||||
let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![cfg_attr(bootstrap, feature(const_panic))]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(let_else)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(trusted_step)]
|
||||
@ -63,7 +63,7 @@ use facts::AllFacts;
|
||||
|
||||
use self::path_utils::*;
|
||||
|
||||
mod borrow_set;
|
||||
pub mod borrow_set;
|
||||
mod borrowck_errors;
|
||||
mod constraint_generation;
|
||||
mod constraints;
|
||||
|
||||
@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.closure_base_def_id(body.source.def_id());
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
if !tcx.has_attr(base_def_id, sym::rustc_regions) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -569,7 +569,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// to store those. Otherwise, we'll pass in `None` to the
|
||||
// functions below, which will trigger them to report errors
|
||||
// eagerly.
|
||||
let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
|
||||
let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
|
||||
|
||||
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
|
||||
@ -689,6 +689,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// them down.
|
||||
let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
|
||||
|
||||
// Convert to the SCC representative: sometimes we have inference
|
||||
// variables in the member constraint that wind up equated with
|
||||
// universal regions. The scc representative is the minimal numbered
|
||||
// one from the corresponding scc so it will be the universal region
|
||||
// if one exists.
|
||||
for c_r in &mut choice_regions {
|
||||
let scc = self.constraint_sccs.scc(*c_r);
|
||||
*c_r = self.scc_representatives[scc];
|
||||
}
|
||||
|
||||
// The 'member region' in a member constraint is part of the
|
||||
// hidden type, which must be in the root universe. Therefore,
|
||||
// it cannot have any placeholders in its value.
|
||||
@ -2100,14 +2110,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
_ => constraint_sup_scc != target_scc,
|
||||
}
|
||||
} else {
|
||||
match categorized_path[*i].category {
|
||||
!matches!(
|
||||
categorized_path[*i].category,
|
||||
ConstraintCategory::OpaqueType
|
||||
| ConstraintCategory::Boring
|
||||
| ConstraintCategory::BoringNoLocation
|
||||
| ConstraintCategory::Internal
|
||||
| ConstraintCategory::Predicate(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
| ConstraintCategory::Boring
|
||||
| ConstraintCategory::BoringNoLocation
|
||||
| ConstraintCategory::Internal
|
||||
| ConstraintCategory::Predicate(_)
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
@ -2219,7 +2229,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||
tcx,
|
||||
closure_substs,
|
||||
self.num_external_vids,
|
||||
tcx.closure_base_def_id(closure_def_id),
|
||||
tcx.typeck_root_def_id(closure_def_id),
|
||||
);
|
||||
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
|
||||
|
||||
|
||||
@ -60,6 +60,11 @@ impl RegionValueElements {
|
||||
PointIndex::new(start_index)
|
||||
}
|
||||
|
||||
/// Return the PointIndex for the block start of this index.
|
||||
crate fn to_block_start(&self, index: PointIndex) -> PointIndex {
|
||||
PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
|
||||
}
|
||||
|
||||
/// Converts a `PointIndex` back to a location. O(1).
|
||||
crate fn to_location(&self, index: PointIndex) -> Location {
|
||||
assert!(index.index() < self.num_points);
|
||||
@ -76,29 +81,6 @@ impl RegionValueElements {
|
||||
crate fn point_in_range(&self, index: PointIndex) -> bool {
|
||||
index.index() < self.num_points
|
||||
}
|
||||
|
||||
/// Pushes all predecessors of `index` onto `stack`.
|
||||
crate fn push_predecessors(
|
||||
&self,
|
||||
body: &Body<'_>,
|
||||
index: PointIndex,
|
||||
stack: &mut Vec<PointIndex>,
|
||||
) {
|
||||
let Location { block, statement_index } = self.to_location(index);
|
||||
if statement_index == 0 {
|
||||
// If this is a basic block head, then the predecessors are
|
||||
// the terminators of other basic blocks
|
||||
stack.extend(
|
||||
body.predecessors()[block]
|
||||
.iter()
|
||||
.map(|&pred_bb| body.terminator_loc(pred_bb))
|
||||
.map(|pred_loc| self.point_from_location(pred_loc)),
|
||||
);
|
||||
} else {
|
||||
// Otherwise, the pred is just the previous statement
|
||||
stack.push(PointIndex::new(index.index() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
|
||||
@ -94,6 +94,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}))),
|
||||
locations,
|
||||
category,
|
||||
|
||||
@ -1,20 +1,18 @@
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::free_regions::FreeRegionRelations;
|
||||
use rustc_infer::infer::outlives;
|
||||
use rustc_infer::infer::region_constraints::GenericKind;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use std::rc::Rc;
|
||||
use type_op::TypeOpOutput;
|
||||
|
||||
use crate::{
|
||||
nll::ToRegionVid,
|
||||
type_check::constraint_conversion,
|
||||
type_check::{Locations, MirTypeckRegionConstraints},
|
||||
universal_regions::UniversalRegions,
|
||||
@ -381,21 +379,3 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is used by the `impl-trait` constraint code to abstract
|
||||
/// over the `FreeRegionMap` from lexical regions and
|
||||
/// `UniversalRegions` (from NLL)`.
|
||||
impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
|
||||
fn sub_free_regions(
|
||||
&self,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
shorter: ty::Region<'tcx>,
|
||||
longer: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
let shorter = shorter.to_region_vid();
|
||||
assert!(self.universal_regions.is_universal_region(shorter));
|
||||
let longer = longer.to_region_vid();
|
||||
assert!(self.universal_regions.is_universal_region(longer));
|
||||
self.outlives(longer, shorter)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,13 +7,16 @@
|
||||
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
|
||||
//! contain revealed `impl Trait` values).
|
||||
|
||||
use crate::type_check::constraint_conversion::ConstraintConversion;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
use type_op::TypeOpOutput;
|
||||
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
@ -30,6 +33,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let (&normalized_output_ty, normalized_input_tys) =
|
||||
normalized_inputs_and_output.split_last().unwrap();
|
||||
|
||||
debug!(?normalized_output_ty);
|
||||
debug!(?normalized_input_tys);
|
||||
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
|
||||
// If the user explicitly annotated the input types, extract
|
||||
@ -75,10 +81,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
.delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
|
||||
break;
|
||||
}
|
||||
|
||||
// In MIR, argument N is stored in local N+1.
|
||||
let local = Local::new(argument_index + 1);
|
||||
|
||||
let mir_input_ty = body.local_decls[local].ty;
|
||||
|
||||
let mir_input_span = body.local_decls[local].source_info.span;
|
||||
self.equate_normalized_input_or_output(
|
||||
normalized_input_ty,
|
||||
@ -100,6 +108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// If the user explicitly annotated the input types, enforce those.
|
||||
let user_provided_input_ty =
|
||||
self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
|
||||
|
||||
self.equate_normalized_input_or_output(
|
||||
user_provided_input_ty,
|
||||
mir_input_ty,
|
||||
@ -167,30 +176,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
|
||||
// like to normalize *before* inserting into `local_decls`, but
|
||||
// doing so ends up causing some other trouble.
|
||||
let b = match self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
|
||||
.normalize(b)
|
||||
{
|
||||
Ok(n) => {
|
||||
debug!("equate_inputs_and_outputs: {:?}", n);
|
||||
if n.obligations.iter().all(|o| {
|
||||
matches!(
|
||||
o.predicate.kind().skip_binder(),
|
||||
ty::PredicateKind::RegionOutlives(_)
|
||||
| ty::PredicateKind::TypeOutlives(_)
|
||||
)
|
||||
}) {
|
||||
n.value
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
let b = match self.normalize_and_add_constraints(b) {
|
||||
Ok(n) => n,
|
||||
Err(_) => {
|
||||
debug!("equate_inputs_and_outputs: NoSolution");
|
||||
b
|
||||
}
|
||||
};
|
||||
|
||||
// Note: if we have to introduce new placeholders during normalization above, then we won't have
|
||||
// added those universes to the universe info, which we would want in `relate_tys`.
|
||||
if let Err(terr) =
|
||||
@ -207,4 +200,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
|
||||
let TypeOpOutput { output: norm_ty, constraints, .. } =
|
||||
self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
|
||||
|
||||
debug!("{:?} normalized to {:?}", t, norm_ty);
|
||||
|
||||
for data in constraints.into_iter().collect::<Vec<_>>() {
|
||||
ConstraintConversion::new(
|
||||
self.infcx,
|
||||
&self.borrowck_context.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
Some(self.implicit_region_bound),
|
||||
self.param_env,
|
||||
Locations::All(DUMMY_SP),
|
||||
ConstraintCategory::Internal,
|
||||
&mut self.borrowck_context.constraints,
|
||||
)
|
||||
.convert_all(&*data);
|
||||
}
|
||||
|
||||
Ok(norm_ty)
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,12 +205,42 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
|
||||
self.stack.extend(self.cx.local_use_map.uses(local));
|
||||
while let Some(p) = self.stack.pop() {
|
||||
if self.defs.contains(p) {
|
||||
continue;
|
||||
}
|
||||
// We are live in this block from the closest to us of:
|
||||
//
|
||||
// * Inclusively, the block start
|
||||
// * Exclusively, the previous definition (if it's in this block)
|
||||
// * Exclusively, the previous live_at setting (an optimization)
|
||||
let block_start = self.cx.elements.to_block_start(p);
|
||||
let previous_defs = self.defs.last_set_in(block_start..=p);
|
||||
let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
|
||||
|
||||
if self.use_live_at.insert(p) {
|
||||
self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack)
|
||||
let exclusive_start = match (previous_defs, previous_live_at) {
|
||||
(Some(a), Some(b)) => Some(std::cmp::max(a, b)),
|
||||
(Some(a), None) | (None, Some(a)) => Some(a),
|
||||
(None, None) => None,
|
||||
};
|
||||
|
||||
if let Some(exclusive) = exclusive_start {
|
||||
self.use_live_at.insert_range(exclusive + 1..=p);
|
||||
|
||||
// If we have a bound after the start of the block, we should
|
||||
// not add the predecessors for this block.
|
||||
continue;
|
||||
} else {
|
||||
// Add all the elements of this block.
|
||||
self.use_live_at.insert_range(block_start..=p);
|
||||
|
||||
// Then add the predecessors for this block, which are the
|
||||
// terminators of predecessor basic blocks. Push those onto the
|
||||
// stack so that the next iteration(s) will process them.
|
||||
|
||||
let block = self.cx.elements.to_location(block_start).block;
|
||||
self.stack.extend(
|
||||
self.cx.body.predecessors()[block]
|
||||
.iter()
|
||||
.map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
|
||||
.map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
@ -36,7 +37,6 @@ use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt};
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::type_op;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
@ -185,7 +185,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
®ion_bound_pairs,
|
||||
implicit_region_bound,
|
||||
&mut borrowck_context,
|
||||
&universal_region_relations,
|
||||
|mut cx| {
|
||||
cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
|
||||
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
|
||||
@ -253,15 +252,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
skip(
|
||||
infcx,
|
||||
body,
|
||||
promoted,
|
||||
region_bound_pairs,
|
||||
borrowck_context,
|
||||
universal_region_relations,
|
||||
extra
|
||||
),
|
||||
skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
|
||||
level = "debug"
|
||||
)]
|
||||
fn type_check_internal<'a, 'tcx, R>(
|
||||
@ -272,7 +263,6 @@ fn type_check_internal<'a, 'tcx, R>(
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
|
||||
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
|
||||
) -> R {
|
||||
let mut checker = TypeChecker::new(
|
||||
@ -282,7 +272,6 @@ fn type_check_internal<'a, 'tcx, R>(
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
universal_region_relations,
|
||||
);
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
|
||||
@ -667,7 +656,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
// If the region is live at at least one location in the promoted MIR,
|
||||
// then add a liveness constraint to the main MIR for this region
|
||||
// at the location provided as an argument to this method
|
||||
if let Some(_) = liveness_constraints.get_elements(region).next() {
|
||||
if liveness_constraints.get_elements(region).next().is_some() {
|
||||
self.cx
|
||||
.borrowck_context
|
||||
.constraints
|
||||
@ -901,15 +890,14 @@ struct TypeChecker<'a, 'tcx> {
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
|
||||
}
|
||||
|
||||
struct BorrowCheckContext<'a, 'tcx> {
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
pub(crate) universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
all_facts: &'a mut Option<AllFacts>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
upvars: &'a [Upvar<'tcx>],
|
||||
}
|
||||
|
||||
@ -1050,7 +1038,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
|
||||
) -> Self {
|
||||
let mut checker = Self {
|
||||
infcx,
|
||||
@ -1062,7 +1049,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
reported_errors: Default::default(),
|
||||
universal_region_relations,
|
||||
};
|
||||
checker.check_user_type_annotations();
|
||||
checker
|
||||
@ -1171,6 +1157,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
|
||||
}
|
||||
|
||||
#[instrument(skip(self, category), level = "debug")]
|
||||
fn eq_types(
|
||||
&mut self,
|
||||
expected: Ty<'tcx>,
|
||||
@ -1322,8 +1309,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
),
|
||||
)?;
|
||||
|
||||
let universal_region_relations = self.universal_region_relations;
|
||||
|
||||
// Finally, if we instantiated the anon types successfully, we
|
||||
// have to solve any bounds (e.g., `-> impl Iterator` needs to
|
||||
// prove that `T: Iterator` where `T` is the type we
|
||||
@ -1335,12 +1320,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.constrain_opaque_type(
|
||||
opaque_type_key,
|
||||
&opaque_decl,
|
||||
GenerateMemberConstraints::IfNoStaticBound,
|
||||
universal_region_relations,
|
||||
);
|
||||
infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
@ -1365,13 +1345,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// though.
|
||||
let category = match place.as_local() {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
|
||||
..
|
||||
} = self.borrowck_context
|
||||
{
|
||||
if tcx.is_static(*def_id) {
|
||||
let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
|
||||
if defining_ty.is_const() {
|
||||
if tcx.is_static(defining_ty.def_id()) {
|
||||
ConstraintCategory::UseAsStatic
|
||||
} else {
|
||||
ConstraintCategory::UseAsConst
|
||||
@ -1549,6 +1525,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
|
||||
self.check_operand(discr, term_location);
|
||||
|
||||
let discr_ty = discr.ty(body, tcx);
|
||||
if let Err(terr) = self.sub_types(
|
||||
discr_ty,
|
||||
@ -1571,6 +1549,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// FIXME: check the values
|
||||
}
|
||||
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
|
||||
self.check_operand(func, term_location);
|
||||
for arg in args {
|
||||
self.check_operand(arg, term_location);
|
||||
}
|
||||
|
||||
let func_ty = func.ty(body, tcx);
|
||||
debug!("check_terminator: call, func_ty={:?}", func_ty);
|
||||
let sig = match func_ty.kind() {
|
||||
@ -1615,6 +1598,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
|
||||
}
|
||||
TerminatorKind::Assert { ref cond, ref msg, .. } => {
|
||||
self.check_operand(cond, term_location);
|
||||
|
||||
let cond_ty = cond.ty(body, tcx);
|
||||
if cond_ty != tcx.types.bool {
|
||||
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
|
||||
@ -1630,6 +1615,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
TerminatorKind::Yield { ref value, .. } => {
|
||||
self.check_operand(value, term_location);
|
||||
|
||||
let value_ty = value.ty(body, tcx);
|
||||
match body.yield_ty() {
|
||||
None => span_mirbug!(self, term, "yield in non-generator"),
|
||||
@ -1672,7 +1659,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
|
||||
UniversalRegions {
|
||||
defining_ty:
|
||||
DefiningTy::Const(def_id, _)
|
||||
| DefiningTy::InlineConst(def_id, _),
|
||||
..
|
||||
},
|
||||
..
|
||||
} = self.borrowck_context
|
||||
{
|
||||
@ -1953,15 +1945,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
||||
if let Operand::Constant(constant) = op {
|
||||
let maybe_uneval = match constant.literal {
|
||||
ConstantKind::Ty(ct) => match ct.val {
|
||||
ty::ConstKind::Unevaluated(uv) => Some(uv),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
if let Some(uv) = maybe_uneval {
|
||||
if uv.promoted.is_none() {
|
||||
let tcx = self.tcx();
|
||||
let def_id = uv.def.def_id_for_type_of();
|
||||
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
||||
let predicates = self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id.expect_local(),
|
||||
uv.substs(tcx),
|
||||
location,
|
||||
);
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id,
|
||||
predicates,
|
||||
location.to_locations(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
let tcx = self.tcx();
|
||||
|
||||
match rvalue {
|
||||
Rvalue::Aggregate(ak, ops) => {
|
||||
for op in ops {
|
||||
self.check_operand(op, location);
|
||||
}
|
||||
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
|
||||
}
|
||||
|
||||
Rvalue::Repeat(operand, len) => {
|
||||
self.check_operand(operand, location);
|
||||
|
||||
// If the length cannot be evaluated we must assume that the length can be larger
|
||||
// than 1.
|
||||
// If the length is larger than 1, the repeat expression will need to copy the
|
||||
@ -2012,7 +2040,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
|
||||
Rvalue::NullaryOp(_, ty) => {
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
};
|
||||
|
||||
self.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::SizedBound,
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::ShallowInitBox(operand, ty) => {
|
||||
self.check_operand(operand, location);
|
||||
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
@ -2026,6 +2069,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
|
||||
Rvalue::Cast(cast_kind, op, ty) => {
|
||||
self.check_operand(op, location);
|
||||
|
||||
match cast_kind {
|
||||
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
|
||||
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
|
||||
@ -2272,6 +2317,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
|
||||
box (left, right),
|
||||
) => {
|
||||
self.check_operand(left, location);
|
||||
self.check_operand(right, location);
|
||||
|
||||
let ty_left = left.ty(body, tcx);
|
||||
match ty_left.kind() {
|
||||
// Types with regions are comparable if they have a common super-type.
|
||||
@ -2322,13 +2370,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
|
||||
self.check_operand(operand, location);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_, box (left, right))
|
||||
| Rvalue::CheckedBinaryOp(_, box (left, right)) => {
|
||||
self.check_operand(left, location);
|
||||
self.check_operand(right, location);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
| Rvalue::Use(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
| Rvalue::Discriminant(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
|
||||
use std::iter;
|
||||
|
||||
use crate::nll::ToRegionVid;
|
||||
@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> {
|
||||
/// is that it has no inputs and a single return value, which is
|
||||
/// the value of the constant.
|
||||
Const(DefId, SubstsRef<'tcx>),
|
||||
|
||||
/// The MIR represents an inline const. The signature has no inputs and a
|
||||
/// single return value found via `InlineConstSubsts::ty`.
|
||||
InlineConst(DefId, SubstsRef<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> DefiningTy<'tcx> {
|
||||
@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
DefiningTy::Generator(_, substs, _) => {
|
||||
Either::Right(Either::Left(substs.as_generator().upvar_tys()))
|
||||
}
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
|
||||
Either::Right(Either::Right(iter::empty()))
|
||||
}
|
||||
}
|
||||
@ -133,22 +137,16 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
pub fn implicit_inputs(self) -> usize {
|
||||
match self {
|
||||
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_fn_def(&self) -> bool {
|
||||
match *self {
|
||||
DefiningTy::FnDef(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(*self, DefiningTy::FnDef(..))
|
||||
}
|
||||
|
||||
pub fn is_const(&self) -> bool {
|
||||
match *self {
|
||||
DefiningTy::Const(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> DefId {
|
||||
@ -156,7 +154,8 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
DefiningTy::Closure(def_id, ..)
|
||||
| DefiningTy::Generator(def_id, ..)
|
||||
| DefiningTy::FnDef(def_id, ..)
|
||||
| DefiningTy::Const(def_id, ..) => def_id,
|
||||
| DefiningTy::Const(def_id, ..)
|
||||
| DefiningTy::InlineConst(def_id, ..) => def_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -248,7 +247,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
closure_substs: SubstsRef<'tcx>,
|
||||
expected_num_vars: usize,
|
||||
closure_base_def_id: DefId,
|
||||
typeck_root_def_id: DefId,
|
||||
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
|
||||
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
|
||||
region_mapping.push(tcx.lifetimes.re_static);
|
||||
@ -256,7 +255,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
region_mapping.push(fr);
|
||||
});
|
||||
|
||||
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
region_mapping.push(r);
|
||||
});
|
||||
|
||||
@ -350,8 +349,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
// tests, and the resulting print-outs include def-ids
|
||||
// and other things that are not stable across tests!
|
||||
// So we just include the region-vid. Annoying.
|
||||
let closure_base_def_id = tcx.closure_base_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
|
||||
});
|
||||
}
|
||||
@ -365,8 +364,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
// FIXME: As above, we'd like to print out the region
|
||||
// `r` but doing so is not stable across architectures
|
||||
// and so forth.
|
||||
let closure_base_def_id = tcx.closure_base_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
|
||||
});
|
||||
}
|
||||
@ -382,6 +381,12 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
tcx.def_path_str_with_substs(def_id, substs),
|
||||
));
|
||||
}
|
||||
DefiningTy::InlineConst(def_id, substs) => {
|
||||
err.note(&format!(
|
||||
"defining inline constant type: {}",
|
||||
tcx.def_path_str_with_substs(def_id, substs),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -417,7 +422,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let mut indices = self.compute_indices(fr_static, defining_ty);
|
||||
debug!("build: indices={:?}", indices);
|
||||
|
||||
let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
|
||||
let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
|
||||
|
||||
// If this is a closure or generator, then the late-bound regions from the enclosing
|
||||
// function are actually external regions to us. For example, here, 'a is not local
|
||||
@ -425,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
// fn foo<'a>() {
|
||||
// let c = || { let x: &'a u32 = ...; }
|
||||
// }
|
||||
if self.mir_def.did.to_def_id() != closure_base_def_id {
|
||||
if self.mir_def.did.to_def_id() != typeck_root_def_id {
|
||||
self.infcx
|
||||
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
|
||||
}
|
||||
@ -443,7 +448,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
);
|
||||
// Converse of above, if this is a function then the late-bound regions declared on its
|
||||
// signature are local to the fn.
|
||||
if self.mir_def.did.to_def_id() == closure_base_def_id {
|
||||
if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
self.infcx
|
||||
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
|
||||
}
|
||||
@ -508,12 +513,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
/// see `DefiningTy` for details.
|
||||
fn defining_ty(&self) -> DefiningTy<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
|
||||
|
||||
match tcx.hir().body_owner_kind(self.mir_hir_id) {
|
||||
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
|
||||
let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
|
||||
tcx.type_of(closure_base_def_id)
|
||||
let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
tcx.type_of(typeck_root_def_id)
|
||||
} else {
|
||||
let tables = tcx.typeck(self.mir_def.did);
|
||||
tables.node_type(self.mir_hir_id)
|
||||
@ -540,11 +545,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
|
||||
assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
|
||||
let substs =
|
||||
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
|
||||
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
|
||||
if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
let substs =
|
||||
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
|
||||
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
|
||||
} else {
|
||||
let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
|
||||
let substs = InlineConstSubsts::new(
|
||||
tcx,
|
||||
InlineConstSubstsParts { parent_substs: identity_substs, ty },
|
||||
)
|
||||
.substs;
|
||||
let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
|
||||
DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -559,17 +574,19 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
defining_ty: DefiningTy<'tcx>,
|
||||
) -> UniversalRegionIndices<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
|
||||
let fr_substs = match defining_ty {
|
||||
DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
|
||||
DefiningTy::Closure(_, ref substs)
|
||||
| DefiningTy::Generator(_, ref substs, _)
|
||||
| DefiningTy::InlineConst(_, ref substs) => {
|
||||
// In the case of closures, we rely on the fact that
|
||||
// the first N elements in the ClosureSubsts are
|
||||
// inherited from the `closure_base_def_id`.
|
||||
// inherited from the `typeck_root_def_id`.
|
||||
// Therefore, when we zip together (below) with
|
||||
// `identity_substs`, we will get only those regions
|
||||
// that correspond to early-bound regions declared on
|
||||
// the `closure_base_def_id`.
|
||||
// the `typeck_root_def_id`.
|
||||
assert!(substs.len() >= identity_substs.len());
|
||||
assert_eq!(substs.regions().count(), identity_substs.regions().count());
|
||||
substs
|
||||
@ -654,6 +671,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let ty = indices.fold_to_region_vids(tcx, ty);
|
||||
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
|
||||
}
|
||||
|
||||
DefiningTy::InlineConst(def_id, substs) => {
|
||||
assert_eq!(self.mir_def.did.to_def_id(), def_id);
|
||||
let ty = substs.as_inline_const().ty();
|
||||
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -742,8 +765,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
) {
|
||||
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
|
||||
let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
|
||||
for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
|
||||
let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
|
||||
for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
|
||||
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.next_nll_region_var(FR);
|
||||
|
||||
@ -19,7 +19,7 @@ struct AsmArgs {
|
||||
operands: Vec<(ast::InlineAsmOperand, Span)>,
|
||||
named_args: FxHashMap<Symbol, usize>,
|
||||
reg_args: FxHashSet<usize>,
|
||||
clobber_abi: Option<(Symbol, Span)>,
|
||||
clobber_abis: Vec<(Symbol, Span)>,
|
||||
options: ast::InlineAsmOptions,
|
||||
options_spans: Vec<Span>,
|
||||
}
|
||||
@ -64,7 +64,7 @@ fn parse_args<'a>(
|
||||
operands: vec![],
|
||||
named_args: FxHashMap::default(),
|
||||
reg_args: FxHashSet::default(),
|
||||
clobber_abi: None,
|
||||
clobber_abis: Vec::new(),
|
||||
options: ast::InlineAsmOptions::empty(),
|
||||
options_spans: vec![],
|
||||
};
|
||||
@ -210,9 +210,9 @@ fn parse_args<'a>(
|
||||
.span_labels(args.options_spans.clone(), "previous options")
|
||||
.span_label(span, "argument")
|
||||
.emit();
|
||||
} else if let Some((_, abi_span)) = args.clobber_abi {
|
||||
} else if let Some((_, abi_span)) = args.clobber_abis.last() {
|
||||
ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
|
||||
.span_label(abi_span, "clobber_abi")
|
||||
.span_label(*abi_span, "clobber_abi")
|
||||
.span_label(span, "argument")
|
||||
.emit();
|
||||
}
|
||||
@ -322,10 +322,13 @@ fn parse_args<'a>(
|
||||
// Bail out now since this is likely to confuse MIR
|
||||
return Err(err);
|
||||
}
|
||||
if let Some((_, abi_span)) = args.clobber_abi {
|
||||
|
||||
if args.clobber_abis.len() > 0 {
|
||||
if is_global_asm {
|
||||
let err =
|
||||
ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`");
|
||||
let err = ecx.struct_span_err(
|
||||
args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
|
||||
"`clobber_abi` cannot be used with `global_asm!`",
|
||||
);
|
||||
|
||||
// Bail out now since this is likely to confuse later stages
|
||||
return Err(err);
|
||||
@ -335,7 +338,10 @@ fn parse_args<'a>(
|
||||
regclass_outputs.clone(),
|
||||
"asm with `clobber_abi` must specify explicit registers for outputs",
|
||||
)
|
||||
.span_label(abi_span, "clobber_abi")
|
||||
.span_labels(
|
||||
args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
|
||||
"clobber_abi",
|
||||
)
|
||||
.span_labels(regclass_outputs, "generic outputs")
|
||||
.emit();
|
||||
}
|
||||
@ -439,37 +445,61 @@ fn parse_clobber_abi<'a>(
|
||||
|
||||
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
|
||||
|
||||
let clobber_abi = match p.parse_str_lit() {
|
||||
Ok(str_lit) => str_lit.symbol_unescaped,
|
||||
Err(opt_lit) => {
|
||||
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
|
||||
let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
|
||||
err.span_label(span, "not a string literal");
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
|
||||
|
||||
let new_span = span_start.to(p.prev_token.span);
|
||||
|
||||
if let Some((_, prev_span)) = args.clobber_abi {
|
||||
let mut err = p
|
||||
.sess
|
||||
.span_diagnostic
|
||||
.struct_span_err(new_span, "clobber_abi specified multiple times");
|
||||
err.span_label(prev_span, "clobber_abi previously specified here");
|
||||
if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
|
||||
let err = p.sess.span_diagnostic.struct_span_err(
|
||||
p.token.span,
|
||||
"at least one abi must be provided as an argument to `clobber_abi`",
|
||||
);
|
||||
return Err(err);
|
||||
} else if !args.options_spans.is_empty() {
|
||||
}
|
||||
|
||||
let mut new_abis = Vec::new();
|
||||
loop {
|
||||
match p.parse_str_lit() {
|
||||
Ok(str_lit) => {
|
||||
new_abis.push((str_lit.symbol_unescaped, str_lit.span));
|
||||
}
|
||||
Err(opt_lit) => {
|
||||
// If the non-string literal is a closing paren then it's the end of the list and is fine
|
||||
if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
|
||||
break;
|
||||
}
|
||||
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
|
||||
let mut err =
|
||||
p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
|
||||
err.span_label(span, "not a string literal");
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Allow trailing commas
|
||||
if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
|
||||
break;
|
||||
}
|
||||
p.expect(&token::Comma)?;
|
||||
}
|
||||
|
||||
let full_span = span_start.to(p.prev_token.span);
|
||||
|
||||
if !args.options_spans.is_empty() {
|
||||
let mut err = p
|
||||
.sess
|
||||
.span_diagnostic
|
||||
.struct_span_err(new_span, "clobber_abi is not allowed after options");
|
||||
.struct_span_err(full_span, "clobber_abi is not allowed after options");
|
||||
err.span_labels(args.options_spans.clone(), "options");
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
args.clobber_abi = Some((clobber_abi, new_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(())
|
||||
}
|
||||
@ -547,7 +577,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
if let Some(snippet) = &template_snippet {
|
||||
if let Some(pos) = snippet.find(needle) {
|
||||
let end = pos
|
||||
+ &snippet[pos..]
|
||||
+ snippet[pos..]
|
||||
.find(|c| matches!(c, '\n' | ';' | '\\' | '"'))
|
||||
.unwrap_or(snippet[pos..].len() - 1);
|
||||
let inner = InnerSpan::new(pos, end);
|
||||
@ -770,7 +800,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
template,
|
||||
template_strs: template_strs.into_boxed_slice(),
|
||||
operands: args.operands,
|
||||
clobber_abi: args.clobber_abi,
|
||||
clobber_abis: args.clobber_abis,
|
||||
options: args.options,
|
||||
line_spans,
|
||||
})
|
||||
@ -812,10 +842,10 @@ pub fn expand_global_asm<'cx>(
|
||||
Ok(args) => {
|
||||
if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
|
||||
MacEager::items(smallvec![P(ast::Item {
|
||||
ident: Ident::invalid(),
|
||||
ident: Ident::empty(),
|
||||
attrs: Vec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ItemKind::GlobalAsm(inline_asm),
|
||||
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
|
||||
vis: ast::Visibility {
|
||||
span: sp.shrink_to_lo(),
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
|
||||
@ -85,7 +85,7 @@ impl MultiItemModifier for Expander {
|
||||
fn dummy_annotatable() -> Annotatable {
|
||||
Annotatable::GenericParam(ast::GenericParam {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
ident: Ident::invalid(),
|
||||
ident: Ident::empty(),
|
||||
attrs: Default::default(),
|
||||
bounds: Default::default(),
|
||||
is_placeholder: false,
|
||||
|
||||
@ -557,12 +557,12 @@ impl<'a> TraitDef<'a> {
|
||||
tokens: None,
|
||||
},
|
||||
attrs: Vec::new(),
|
||||
kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAliasKind(
|
||||
ast::Defaultness::Final,
|
||||
Generics::default(),
|
||||
Vec::new(),
|
||||
Some(type_def.to_ty(cx, self.span, type_ident, generics)),
|
||||
))),
|
||||
kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
generics: Generics::default(),
|
||||
bounds: Vec::new(),
|
||||
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
|
||||
})),
|
||||
tokens: None,
|
||||
})
|
||||
});
|
||||
@ -724,9 +724,9 @@ impl<'a> TraitDef<'a> {
|
||||
|
||||
cx.item(
|
||||
self.span,
|
||||
Ident::invalid(),
|
||||
Ident::empty(),
|
||||
a,
|
||||
ast::ItemKind::Impl(Box::new(ast::ImplKind {
|
||||
ast::ItemKind::Impl(Box::new(ast::Impl {
|
||||
unsafety,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
@ -955,7 +955,7 @@ impl<'a> MethodDef<'a> {
|
||||
decl: fn_decl,
|
||||
span: trait_.span,
|
||||
};
|
||||
let def = ast::Defaultness::Final;
|
||||
let defaultness = ast::Defaultness::Final;
|
||||
|
||||
// Create the method.
|
||||
P(ast::AssocItem {
|
||||
@ -968,12 +968,12 @@ impl<'a> MethodDef<'a> {
|
||||
tokens: None,
|
||||
},
|
||||
ident: method_ident,
|
||||
kind: ast::AssocItemKind::Fn(Box::new(ast::FnKind(
|
||||
def,
|
||||
kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
|
||||
defaultness,
|
||||
sig,
|
||||
fn_generics,
|
||||
Some(body_block),
|
||||
))),
|
||||
generics: fn_generics,
|
||||
body: Some(body_block),
|
||||
})),
|
||||
tokens: None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{ImplKind, ItemKind, MetaItem};
|
||||
use rustc_ast::{Impl, ItemKind, MetaItem};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
@ -178,9 +178,9 @@ fn inject_impl_of_structural_trait(
|
||||
|
||||
let newitem = cx.item(
|
||||
span,
|
||||
Ident::invalid(),
|
||||
Ident::empty(),
|
||||
attrs,
|
||||
ItemKind::Impl(Box::new(ImplKind {
|
||||
ItemKind::Impl(Box::new(Impl {
|
||||
unsafety: ast::Unsafe::No,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
|
||||
@ -527,17 +527,9 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
self.verify_arg_type(Exact(idx), ty)
|
||||
}
|
||||
None => {
|
||||
let capture_feature_enabled = self
|
||||
.ecx
|
||||
.ecfg
|
||||
.features
|
||||
.map_or(false, |features| features.format_args_capture);
|
||||
|
||||
// For the moment capturing variables from format strings expanded from macros is
|
||||
// disabled (see RFC #2795)
|
||||
let can_capture = capture_feature_enabled && self.is_literal;
|
||||
|
||||
if can_capture {
|
||||
if self.is_literal {
|
||||
// Treat this name as a variable to capture from the surrounding scope
|
||||
let idx = self.args.len();
|
||||
self.arg_types.push(Vec::new());
|
||||
@ -559,23 +551,15 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
};
|
||||
let mut err = self.ecx.struct_span_err(sp, &msg[..]);
|
||||
|
||||
if capture_feature_enabled && !self.is_literal {
|
||||
err.note(&format!(
|
||||
"did you intend to capture a variable `{}` from \
|
||||
the surrounding scope?",
|
||||
name
|
||||
));
|
||||
err.note(
|
||||
"to avoid ambiguity, `format_args!` cannot capture variables \
|
||||
when the format string is expanded from a macro",
|
||||
);
|
||||
} else if self.ecx.parse_sess().unstable_features.is_nightly_build() {
|
||||
err.help(&format!(
|
||||
"if you intended to capture `{}` from the surrounding scope, add \
|
||||
`#![feature(format_args_capture)]` to the crate attributes",
|
||||
name
|
||||
));
|
||||
}
|
||||
err.note(&format!(
|
||||
"did you intend to capture a variable `{}` from \
|
||||
the surrounding scope?",
|
||||
name
|
||||
));
|
||||
err.note(
|
||||
"to avoid ambiguity, `format_args!` cannot capture variables \
|
||||
when the format string is expanded from a macro",
|
||||
);
|
||||
|
||||
err.emit();
|
||||
}
|
||||
@ -760,16 +744,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
/// Actually builds the expression which the format_args! block will be
|
||||
/// expanded to.
|
||||
fn into_expr(self) -> P<ast::Expr> {
|
||||
let mut locals =
|
||||
Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum());
|
||||
let mut counts = Vec::with_capacity(self.count_args.len());
|
||||
let mut pats = Vec::with_capacity(self.args.len());
|
||||
let mut args = Vec::with_capacity(
|
||||
self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
|
||||
);
|
||||
let mut heads = Vec::with_capacity(self.args.len());
|
||||
|
||||
let names_pos: Vec<_> = (0..self.args.len())
|
||||
.map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
|
||||
.collect();
|
||||
|
||||
// First, build up the static array which will become our precompiled
|
||||
// format "string"
|
||||
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
|
||||
@ -787,11 +766,8 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
// of each variable because we don't want to move out of the arguments
|
||||
// passed to this function.
|
||||
for (i, e) in self.args.into_iter().enumerate() {
|
||||
let name = names_pos[i];
|
||||
let span = self.ecx.with_def_site_ctxt(e.span);
|
||||
pats.push(self.ecx.pat_ident(span, name));
|
||||
for arg_ty in self.arg_unique_types[i].iter() {
|
||||
locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
|
||||
args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
|
||||
}
|
||||
heads.push(self.ecx.expr_addr_of(e.span, e));
|
||||
}
|
||||
@ -800,15 +776,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
Exact(i) => i,
|
||||
_ => panic!("should never happen"),
|
||||
};
|
||||
let name = names_pos[index];
|
||||
let span = spans_pos[index];
|
||||
counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name));
|
||||
args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
|
||||
}
|
||||
|
||||
// Now create a vector containing all the arguments
|
||||
let args = locals.into_iter().chain(counts.into_iter());
|
||||
|
||||
let args_array = self.ecx.expr_vec(self.macsp, args.collect());
|
||||
let args_array = self.ecx.expr_vec(self.macsp, args);
|
||||
|
||||
// Constructs an AST equivalent to:
|
||||
//
|
||||
@ -838,7 +810,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
// But the nested match expression is proved to perform not as well
|
||||
// as series of let's; the first approach does.
|
||||
let args_match = {
|
||||
let pat = self.ecx.pat_tuple(self.macsp, pats);
|
||||
let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp));
|
||||
let arm = self.ecx.arm(self.macsp, pat, args_array);
|
||||
let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
|
||||
self.ecx.expr_match(self.macsp, head, vec![arm])
|
||||
@ -877,10 +849,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
macsp: Span,
|
||||
mut sp: Span,
|
||||
ty: &ArgumentType,
|
||||
arg: Ident,
|
||||
arg_index: usize,
|
||||
) -> P<ast::Expr> {
|
||||
sp = ecx.with_def_site_ctxt(sp);
|
||||
let arg = ecx.expr_ident(sp, arg);
|
||||
let arg = ecx.expr_ident(sp, Ident::new(sym::_args, sp));
|
||||
let arg = ecx.expr(sp, ast::ExprKind::Field(arg, Ident::new(sym::integer(arg_index), sp)));
|
||||
let trait_ = match *ty {
|
||||
Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
|
||||
Placeholder(trait_) => trait_,
|
||||
|
||||
@ -5,7 +5,7 @@ use rustc_ast::expand::allocator::{
|
||||
};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
|
||||
use rustc_ast::{FnKind, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
|
||||
use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
@ -84,13 +84,13 @@ impl AllocFnFactory<'_, '_> {
|
||||
let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
|
||||
let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
|
||||
let sig = FnSig { decl, header, span: self.span };
|
||||
let block = Some(self.cx.block_expr(output_expr));
|
||||
let kind = ItemKind::Fn(Box::new(FnKind(
|
||||
ast::Defaultness::Final,
|
||||
let body = Some(self.cx.block_expr(output_expr));
|
||||
let kind = ItemKind::Fn(Box::new(Fn {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
sig,
|
||||
Generics::default(),
|
||||
block,
|
||||
)));
|
||||
generics: Generics::default(),
|
||||
body,
|
||||
}));
|
||||
let item = self.cx.item(
|
||||
self.span,
|
||||
Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
|
||||
|
||||
@ -77,7 +77,7 @@ pub fn inject(
|
||||
|
||||
let use_item = cx.item(
|
||||
span,
|
||||
Ident::invalid(),
|
||||
Ident::empty(),
|
||||
vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
|
||||
ast::ItemKind::Use(ast::UseTree {
|
||||
prefix: cx.path(span, import_path),
|
||||
|
||||
@ -429,7 +429,7 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
|
||||
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
|
||||
let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
|
||||
let sd = &cx.sess.parse_sess.span_diagnostic;
|
||||
if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, ref generics, _)) = i.kind {
|
||||
if let ast::ItemKind::Fn(box ast::Fn { ref sig, ref generics, .. }) = i.kind {
|
||||
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
|
||||
sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
|
||||
.span_label(span, "`unsafe` because of this")
|
||||
@ -478,7 +478,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
|
||||
}
|
||||
|
||||
fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
|
||||
let has_sig = if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) = i.kind {
|
||||
let has_sig = if let ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) = i.kind {
|
||||
// N.B., inadequate check, but we're running
|
||||
// well before resolve, can't get too deep.
|
||||
sig.decl.inputs.len() == 1
|
||||
|
||||
@ -313,13 +313,13 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
|
||||
|
||||
let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty));
|
||||
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
|
||||
let def = ast::Defaultness::Final;
|
||||
let main = ast::ItemKind::Fn(Box::new(ast::FnKind(
|
||||
def,
|
||||
let defaultness = ast::Defaultness::Final;
|
||||
let main = ast::ItemKind::Fn(Box::new(ast::Fn {
|
||||
defaultness,
|
||||
sig,
|
||||
ast::Generics::default(),
|
||||
Some(main_body),
|
||||
)));
|
||||
generics: ast::Generics::default(),
|
||||
body: Some(main_body),
|
||||
}));
|
||||
|
||||
// Honor the reexport_test_harness_main attribute
|
||||
let main_id = match cx.reexport_test_harness_main {
|
||||
|
||||
@ -224,7 +224,7 @@ pub(crate) fn run_aot(
|
||||
tcx,
|
||||
(backend_config.clone(), cgu.name()),
|
||||
module_codegen,
|
||||
rustc_middle::dep_graph::hash_result,
|
||||
Some(rustc_middle::dep_graph::hash_result),
|
||||
);
|
||||
|
||||
if let Some((id, product)) = work_product {
|
||||
|
||||
@ -14,7 +14,7 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
// TODO(antoyo)
|
||||
}
|
||||
|
||||
fn get_param(&self, index: usize) -> Self::Value {
|
||||
fn get_param(&mut self, index: usize) -> Self::Value {
|
||||
self.cx.current_func.borrow().expect("current func")
|
||||
.get_param(index as i32)
|
||||
.to_rvalue()
|
||||
|
||||
@ -118,7 +118,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
true
|
||||
}
|
||||
|
||||
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
|
||||
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
|
||||
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
||||
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
|
||||
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
|
||||
|
||||
@ -59,7 +59,13 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (Modul
|
||||
let start_time = Instant::now();
|
||||
|
||||
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
|
||||
let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
|
||||
let (module, _) = tcx.dep_graph.with_task(
|
||||
dep_node,
|
||||
tcx,
|
||||
cgu_name,
|
||||
module_codegen,
|
||||
Some(dep_graph::hash_result),
|
||||
);
|
||||
let time_to_codegen = start_time.elapsed();
|
||||
drop(prof_timer);
|
||||
|
||||
|
||||
@ -915,6 +915,16 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
// TODO(antoyo)
|
||||
}
|
||||
|
||||
fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
|
||||
// Unsupported.
|
||||
}
|
||||
|
||||
fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
|
||||
// Unsupported.
|
||||
self.context.new_rvalue_from_int(self.int_type, 0)
|
||||
}
|
||||
|
||||
|
||||
fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
|
||||
self.store_with_flags(val, ptr, align, MemFlags::empty())
|
||||
}
|
||||
|
||||
@ -316,7 +316,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
extended_asm.add_input_operand(None, "r", result.llval);
|
||||
extended_asm.add_clobber("memory");
|
||||
extended_asm.set_volatile_flag(true);
|
||||
|
||||
|
||||
// We have copied the value to `result` already.
|
||||
return;
|
||||
}
|
||||
@ -363,8 +363,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
cond
|
||||
}
|
||||
|
||||
fn sideeffect(&mut self) {
|
||||
// TODO(antoyo)
|
||||
fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
|
||||
// Unsupported.
|
||||
self.context.new_rvalue_from_int(self.int_type, 0)
|
||||
}
|
||||
|
||||
fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
|
||||
|
||||
@ -11,7 +11,7 @@ doctest = false
|
||||
bitflags = "1.0"
|
||||
cstr = "0.2"
|
||||
libc = "0.2"
|
||||
measureme = "9.1.0"
|
||||
measureme = "10.0.0"
|
||||
snap = "1"
|
||||
tracing = "0.1"
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::llvm::{self, AttributePlace};
|
||||
use crate::llvm_util;
|
||||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
@ -53,15 +52,10 @@ pub trait ArgAttributesExt {
|
||||
}
|
||||
|
||||
fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
|
||||
// LLVM prior to version 12 has known miscompiles in the presence of
|
||||
// noalias attributes (see #54878). Only enable mutable noalias by
|
||||
// default for versions we believe to be safe.
|
||||
cx.tcx
|
||||
.sess
|
||||
.opts
|
||||
.debugging_opts
|
||||
.mutable_noalias
|
||||
.unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0))
|
||||
// LLVM prior to version 12 had known miscompiles in the presence of
|
||||
// noalias attributes (see #54878), but we don't support earlier
|
||||
// versions at all anymore. We now enable mutable noalias by default.
|
||||
cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true)
|
||||
}
|
||||
|
||||
impl ArgAttributesExt for ArgAttributes {
|
||||
@ -613,7 +607,7 @@ impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
fn_abi.apply_attrs_callsite(self, callsite)
|
||||
}
|
||||
|
||||
fn get_param(&self, index: usize) -> Self::Value {
|
||||
fn get_param(&mut self, index: usize) -> Self::Value {
|
||||
llvm::get_param(self.llfn(), index as c_uint)
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_middle::{bug, span_bug, ty::Instance};
|
||||
use rustc_span::{Pos, Span, Symbol};
|
||||
use rustc_target::abi::*;
|
||||
use rustc_target::asm::*;
|
||||
@ -120,6 +120,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
operands: &[InlineAsmOperandRef<'tcx, Self>],
|
||||
options: InlineAsmOptions,
|
||||
line_spans: &[Span],
|
||||
instance: Instance<'_>,
|
||||
) {
|
||||
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
||||
|
||||
@ -135,7 +136,10 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
let is_target_supported = |reg_class: InlineAsmRegClass| {
|
||||
for &(_, feature) in reg_class.supported_types(asm_arch) {
|
||||
if let Some(feature) = feature {
|
||||
if self.tcx.sess.target_features.contains(&Symbol::intern(feature))
|
||||
let codegen_fn_attrs = self.tcx.codegen_fn_attrs(instance.def_id());
|
||||
let feature_name = Symbol::intern(feature);
|
||||
if self.tcx.sess.target_features.contains(&feature_name)
|
||||
|| codegen_fn_attrs.target_features.contains(&feature_name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -316,7 +320,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
|
||||
InlineAsmArch::S390x => {}
|
||||
InlineAsmArch::SpirV => {}
|
||||
InlineAsmArch::Wasm32 => {}
|
||||
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
|
||||
InlineAsmArch::Bpf => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
|
||||
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
|
||||
|
||||
use crate::attributes;
|
||||
use crate::llvm::AttributePlace::Function;
|
||||
@ -161,6 +161,17 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_stackprotector(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
|
||||
let sspattr = match cx.sess().stack_protector() {
|
||||
StackProtector::None => return,
|
||||
StackProtector::All => Attribute::StackProtectReq,
|
||||
StackProtector::Strong => Attribute::StackProtectStrong,
|
||||
StackProtector::Basic => Attribute::StackProtect,
|
||||
};
|
||||
|
||||
sspattr.apply_llfn(Function, llfn)
|
||||
}
|
||||
|
||||
pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
|
||||
let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess));
|
||||
llvm::AddFunctionAttrStringValue(
|
||||
@ -271,6 +282,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
|
||||
set_frame_pointer_type(cx, llfn);
|
||||
set_instrument_function(cx, llfn);
|
||||
set_probestack(cx, llfn);
|
||||
set_stackprotector(cx, llfn);
|
||||
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
|
||||
Attribute::Cold.apply_llfn(Function, llfn);
|
||||
|
||||
@ -17,6 +17,7 @@ use rustc_codegen_ssa::back::write::{
|
||||
};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_errors::{FatalError, Handler, Level};
|
||||
use rustc_fs_util::{link_or_copy, path_to_c_string};
|
||||
@ -53,6 +54,7 @@ pub fn write_output_file(
|
||||
output: &Path,
|
||||
dwo_output: Option<&Path>,
|
||||
file_type: llvm::FileType,
|
||||
self_profiler_ref: &SelfProfilerRef,
|
||||
) -> Result<(), FatalError> {
|
||||
unsafe {
|
||||
let output_c = path_to_c_string(output);
|
||||
@ -76,6 +78,19 @@ pub fn write_output_file(
|
||||
file_type,
|
||||
)
|
||||
};
|
||||
|
||||
// Record artifact sizes for self-profiling
|
||||
if result == llvm::LLVMRustResult::Success {
|
||||
let artifact_kind = match file_type {
|
||||
llvm::FileType::ObjectFile => "object_file",
|
||||
llvm::FileType::AssemblyFile => "assembly_file",
|
||||
};
|
||||
record_artifact_size(self_profiler_ref, artifact_kind, output);
|
||||
if let Some(dwo_file) = dwo_output {
|
||||
record_artifact_size(self_profiler_ref, "dwo_file", dwo_file);
|
||||
}
|
||||
}
|
||||
|
||||
result.into_result().map_err(|()| {
|
||||
let msg = format!("could not write output to {}", output.display());
|
||||
llvm_err(handler, &msg)
|
||||
@ -161,6 +176,7 @@ pub fn target_machine_factory(
|
||||
let ffunction_sections =
|
||||
sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections);
|
||||
let fdata_sections = ffunction_sections;
|
||||
let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names;
|
||||
|
||||
let code_model = to_llvm_code_model(sess.code_model());
|
||||
|
||||
@ -205,6 +221,7 @@ pub fn target_machine_factory(
|
||||
use_softfp,
|
||||
ffunction_sections,
|
||||
fdata_sections,
|
||||
funique_section_names,
|
||||
trap_unreachable,
|
||||
singlethread,
|
||||
asm_comments,
|
||||
@ -284,7 +301,7 @@ fn report_inline_asm(
|
||||
cookie = 0;
|
||||
}
|
||||
let level = match level {
|
||||
llvm::DiagnosticLevel::Error => Level::Error,
|
||||
llvm::DiagnosticLevel::Error => Level::Error { lint: false },
|
||||
llvm::DiagnosticLevel::Warning => Level::Warning,
|
||||
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
|
||||
};
|
||||
@ -746,6 +763,14 @@ pub(crate) unsafe fn codegen(
|
||||
let thin = ThinBuffer::new(llmod);
|
||||
let data = thin.data();
|
||||
|
||||
if let Some(bitcode_filename) = bc_out.file_name() {
|
||||
cgcx.prof.artifact_size(
|
||||
"llvm_bitcode",
|
||||
bitcode_filename.to_string_lossy(),
|
||||
data.len() as u64,
|
||||
);
|
||||
}
|
||||
|
||||
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||
"LLVM_module_codegen_emit_bitcode",
|
||||
@ -806,6 +831,11 @@ pub(crate) unsafe fn codegen(
|
||||
}
|
||||
|
||||
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
|
||||
|
||||
if result == llvm::LLVMRustResult::Success {
|
||||
record_artifact_size(&cgcx.prof, "llvm_ir", &out);
|
||||
}
|
||||
|
||||
result.into_result().map_err(|()| {
|
||||
let msg = format!("failed to write LLVM IR to {}", out.display());
|
||||
llvm_err(diag_handler, &msg)
|
||||
@ -836,6 +866,7 @@ pub(crate) unsafe fn codegen(
|
||||
&path,
|
||||
None,
|
||||
llvm::FileType::AssemblyFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
@ -869,6 +900,7 @@ pub(crate) unsafe fn codegen(
|
||||
&obj_out,
|
||||
dwo_out,
|
||||
llvm::FileType::ObjectFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
@ -1125,3 +1157,19 @@ fn create_msvc_imps(
|
||||
symbol_name.starts_with(b"__llvm_profile_")
|
||||
}
|
||||
}
|
||||
|
||||
fn record_artifact_size(
|
||||
self_profiler_ref: &SelfProfilerRef,
|
||||
artifact_kind: &'static str,
|
||||
path: &Path,
|
||||
) {
|
||||
// Don't stat the file if we are not going to record its size.
|
||||
if !self_profiler_ref.enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(artifact_name) = path.file_name() {
|
||||
let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
|
||||
self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,8 +113,13 @@ pub fn compile_codegen_unit(
|
||||
let start_time = Instant::now();
|
||||
|
||||
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
|
||||
let (module, _) =
|
||||
tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
|
||||
let (module, _) = tcx.dep_graph.with_task(
|
||||
dep_node,
|
||||
tcx,
|
||||
cgu_name,
|
||||
module_codegen,
|
||||
Some(dep_graph::hash_result),
|
||||
);
|
||||
let time_to_codegen = start_time.elapsed();
|
||||
|
||||
// We assume that the cost to run LLVM on a CGU is proportional to
|
||||
|
||||
@ -604,6 +604,32 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
|
||||
let typeid_metadata = self.typeid_metadata(typeid);
|
||||
let v = [self.const_usize(0), typeid_metadata];
|
||||
unsafe {
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
function,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
|
||||
self.cx.llcx,
|
||||
v.as_ptr(),
|
||||
v.len() as c_uint,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
|
||||
unsafe {
|
||||
llvm::LLVMMDStringInContext(
|
||||
self.cx.llcx,
|
||||
typeid.as_ptr() as *const c_char,
|
||||
typeid.as_bytes().len() as c_uint,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
|
||||
self.store_with_flags(val, ptr, align, MemFlags::empty())
|
||||
}
|
||||
@ -705,7 +731,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
}
|
||||
|
||||
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
|
||||
if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
|
||||
if !self.fptoint_sat_broken_in_llvm() {
|
||||
let src_ty = self.cx.val_ty(val);
|
||||
let float_width = self.cx.float_width(src_ty);
|
||||
let int_width = self.cx.int_width(dest_ty);
|
||||
@ -717,7 +743,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
}
|
||||
|
||||
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
|
||||
if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
|
||||
if !self.fptoint_sat_broken_in_llvm() {
|
||||
let src_ty = self.cx.val_ty(val);
|
||||
let float_width = self.cx.float_width(src_ty);
|
||||
let int_width = self.cx.int_width(dest_ty);
|
||||
@ -743,7 +769,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
// we like. To ensure that LLVM picks the right instruction we choose
|
||||
// the raw wasm intrinsic functions which avoid LLVM inserting all the
|
||||
// other control flow automatically.
|
||||
if self.sess().target.arch == "wasm32" {
|
||||
if self.sess().target.is_like_wasm {
|
||||
let src_ty = self.cx.val_ty(val);
|
||||
if self.cx.type_kind(src_ty) != TypeKind::Vector {
|
||||
let float_width = self.cx.float_width(src_ty);
|
||||
@ -765,7 +791,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
|
||||
fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
||||
// see `fptoui` above for why wasm is different here
|
||||
if self.sess().target.arch == "wasm32" {
|
||||
if self.sess().target.is_like_wasm {
|
||||
let src_ty = self.cx.val_ty(val);
|
||||
if self.cx.type_kind(src_ty) != TypeKind::Vector {
|
||||
let float_width = self.cx.float_width(src_ty);
|
||||
|
||||
@ -490,7 +490,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
|
||||
|
||||
// Wasm statics with custom link sections get special treatment as they
|
||||
// go into custom sections of the wasm executable.
|
||||
if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
|
||||
if self.tcx.sess.target.is_like_wasm {
|
||||
if let Some(section) = attrs.link_section {
|
||||
let section = llvm::LLVMMDStringInContext(
|
||||
self.llcx,
|
||||
|
||||
@ -134,9 +134,6 @@ pub unsafe fn create_module(
|
||||
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
|
||||
|
||||
let mut target_data_layout = sess.target.data_layout.clone();
|
||||
if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
|
||||
target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
|
||||
}
|
||||
if llvm_util::get_version() < (13, 0, 0) {
|
||||
if sess.target.arch == "powerpc64" {
|
||||
target_data_layout = target_data_layout.replace("-S128", "");
|
||||
@ -221,6 +218,15 @@ pub unsafe fn create_module(
|
||||
llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
|
||||
}
|
||||
|
||||
if sess.is_sanitizer_cfi_enabled() {
|
||||
// FIXME(rcvalle): Add support for non canonical jump tables.
|
||||
let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
|
||||
// FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with
|
||||
// Warning behavior flag. Add support for specifying the behavior flag to
|
||||
// LLVMRustAddModuleFlag.
|
||||
llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1);
|
||||
}
|
||||
|
||||
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
|
||||
if sess.target.is_like_msvc {
|
||||
match sess.opts.cg.control_flow_guard {
|
||||
@ -591,7 +597,6 @@ impl CodegenCx<'b, 'tcx> {
|
||||
ifn!("llvm.trap", fn() -> void);
|
||||
ifn!("llvm.debugtrap", fn() -> void);
|
||||
ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
|
||||
ifn!("llvm.sideeffect", fn() -> void);
|
||||
|
||||
ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
|
||||
ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
|
||||
@ -779,6 +784,8 @@ impl CodegenCx<'b, 'tcx> {
|
||||
ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
|
||||
}
|
||||
|
||||
ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1);
|
||||
|
||||
if self.sess().opts.debuginfo != DebugInfo::None {
|
||||
ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void);
|
||||
ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void);
|
||||
|
||||
@ -322,7 +322,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
|
||||
|
||||
// Find the enclosing function, in case this is a closure.
|
||||
let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
|
||||
let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
|
||||
|
||||
// Get_template_parameters() will append a `<...>` clause to the function
|
||||
// name if necessary.
|
||||
|
||||
@ -19,7 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{sym, symbol::kw, Span, Symbol};
|
||||
use rustc_target::abi::{self, HasDataLayout, Primitive};
|
||||
use rustc_target::abi::{self, Align, HasDataLayout, Primitive};
|
||||
use rustc_target::spec::{HasTargetSpec, PanicStrategy};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
@ -392,13 +392,12 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
|
||||
}
|
||||
|
||||
fn sideeffect(&mut self) {
|
||||
// This kind of check would make a ton of sense in the caller, but currently the only
|
||||
// caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM
|
||||
// codegen backend being used, and so is unable to check the LLVM version.
|
||||
if unsafe { llvm::LLVMRustVersionMajor() } < 12 {
|
||||
self.call_intrinsic("llvm.sideeffect", &[]);
|
||||
}
|
||||
fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
|
||||
// Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
|
||||
// optimization pass replaces calls to this intrinsic with code to test type membership.
|
||||
let i8p_ty = self.type_i8p();
|
||||
let bitcast = self.bitcast(pointer, i8p_ty);
|
||||
self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
|
||||
}
|
||||
|
||||
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||
@ -849,28 +848,39 @@ fn generic_simd_intrinsic(
|
||||
let arg_tys = sig.inputs();
|
||||
|
||||
if name == sym::simd_select_bitmask {
|
||||
let in_ty = arg_tys[0];
|
||||
let m_len = match in_ty.kind() {
|
||||
// Note that this `.unwrap()` crashes for isize/usize, that's sort
|
||||
// of intentional as there's not currently a use case for that.
|
||||
ty::Int(i) => i.bit_width().unwrap(),
|
||||
ty::Uint(i) => i.bit_width().unwrap(),
|
||||
_ => return_error!("`{}` is not an integral type", in_ty),
|
||||
};
|
||||
require_simd!(arg_tys[1], "argument");
|
||||
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
// Allow masks for vectors with fewer than 8 elements to be
|
||||
// represented with a u8 or i8.
|
||||
m_len == v_len || (m_len == 8 && v_len < 8),
|
||||
"mismatched lengths: mask length `{}` != other vector length `{}`",
|
||||
m_len,
|
||||
v_len
|
||||
);
|
||||
let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
|
||||
let expected_int_bits = (len.max(8) - 1).next_power_of_two();
|
||||
let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
|
||||
|
||||
let mask_ty = arg_tys[0];
|
||||
let mask = match mask_ty.kind() {
|
||||
ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
{
|
||||
let place = PlaceRef::alloca(bx, args[0].layout);
|
||||
args[0].val.store(bx, place);
|
||||
let int_ty = bx.type_ix(expected_bytes * 8);
|
||||
let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
|
||||
bx.load(int_ty, ptr, Align::ONE)
|
||||
}
|
||||
_ => return_error!(
|
||||
"invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
|
||||
mask_ty,
|
||||
expected_int_bits,
|
||||
expected_bytes
|
||||
),
|
||||
};
|
||||
|
||||
let i1 = bx.type_i1();
|
||||
let im = bx.type_ix(v_len);
|
||||
let i1xn = bx.type_vector(i1, v_len);
|
||||
let m_im = bx.trunc(args[0].immediate(), im);
|
||||
let im = bx.type_ix(len);
|
||||
let i1xn = bx.type_vector(i1, len);
|
||||
let m_im = bx.trunc(mask, im);
|
||||
let m_i1s = bx.bitcast(m_im, i1xn);
|
||||
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
|
||||
}
|
||||
@ -1048,16 +1058,16 @@ fn generic_simd_intrinsic(
|
||||
|
||||
if name == sym::simd_bitmask {
|
||||
// The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
|
||||
// vector mask and returns an unsigned integer containing the most
|
||||
// significant bit (MSB) of each lane.
|
||||
|
||||
// If the vector has less than 8 lanes, a u8 is returned with zeroed
|
||||
// trailing bits.
|
||||
// vector mask and returns the most significant bit (MSB) of each lane in the form
|
||||
// of either:
|
||||
// * an unsigned integer
|
||||
// * an array of `u8`
|
||||
// If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
|
||||
//
|
||||
// The bit order of the result depends on the byte endianness, LSB-first for little
|
||||
// endian and MSB-first for big endian.
|
||||
let expected_int_bits = in_len.max(8);
|
||||
match ret_ty.kind() {
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (),
|
||||
_ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits),
|
||||
}
|
||||
let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
|
||||
|
||||
// Integer vector <i{in_bitwidth} x in_len>:
|
||||
let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
|
||||
@ -1087,8 +1097,34 @@ fn generic_simd_intrinsic(
|
||||
let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len));
|
||||
// Bitcast <i1 x N> to iN:
|
||||
let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
|
||||
// Zero-extend iN to the bitmask type:
|
||||
return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
|
||||
|
||||
match ret_ty.kind() {
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
|
||||
// Zero-extend iN to the bitmask type:
|
||||
return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
|
||||
}
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
{
|
||||
// Zero-extend iN to the array lengh:
|
||||
let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
|
||||
|
||||
// Convert the integer to a byte array
|
||||
let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE);
|
||||
bx.store(ze, ptr, Align::ONE);
|
||||
let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
|
||||
let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
|
||||
return Ok(bx.load(array_ty, ptr, Align::ONE));
|
||||
}
|
||||
_ => return_error!(
|
||||
"cannot return `{}`, expected `u{}` or `[u8; {}]`",
|
||||
ret_ty,
|
||||
expected_int_bits,
|
||||
expected_bytes
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn simd_simple_float_intrinsic(
|
||||
|
||||
@ -76,6 +76,27 @@ mod value;
|
||||
#[derive(Clone)]
|
||||
pub struct LlvmCodegenBackend(());
|
||||
|
||||
struct TimeTraceProfiler {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl TimeTraceProfiler {
|
||||
fn new(enabled: bool) -> Self {
|
||||
if enabled {
|
||||
unsafe { llvm::LLVMTimeTraceProfilerInitialize() }
|
||||
}
|
||||
TimeTraceProfiler { enabled }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TimeTraceProfiler {
|
||||
fn drop(&mut self) {
|
||||
if self.enabled {
|
||||
unsafe { llvm::LLVMTimeTraceProfilerFinishThread() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtraBackendMethods for LlvmCodegenBackend {
|
||||
fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
|
||||
ModuleLlvm::new_metadata(tcx, mod_name)
|
||||
@ -119,6 +140,34 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
|
||||
fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
|
||||
llvm_util::tune_cpu(sess)
|
||||
}
|
||||
|
||||
fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
std::thread::spawn(move || {
|
||||
let _profiler = TimeTraceProfiler::new(time_trace);
|
||||
f()
|
||||
})
|
||||
}
|
||||
|
||||
fn spawn_named_thread<F, T>(
|
||||
time_trace: bool,
|
||||
name: String,
|
||||
f: F,
|
||||
) -> std::io::Result<std::thread::JoinHandle<T>>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
std::thread::Builder::new().name(name).spawn(move || {
|
||||
let _profiler = TimeTraceProfiler::new(time_trace);
|
||||
f()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteBackendMethods for LlvmCodegenBackend {
|
||||
@ -239,6 +288,31 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||
}
|
||||
println!();
|
||||
}
|
||||
PrintRequest::StackProtectorStrategies => {
|
||||
println!(
|
||||
r#"Available stack protector strategies:
|
||||
all
|
||||
Generate stack canaries in all functions.
|
||||
|
||||
strong
|
||||
Generate stack canaries in a function if it either:
|
||||
- has a local variable of `[T; N]` type, regardless of `T` and `N`
|
||||
- takes the address of a local variable.
|
||||
|
||||
(Note that a local variable being borrowed is not equivalent to its
|
||||
address being taken: e.g. some borrows may be removed by optimization,
|
||||
while by-value argument passing may be implemented with reference to a
|
||||
local stack variable in the ABI.)
|
||||
|
||||
basic
|
||||
Generate stack canaries in functions with:
|
||||
- local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
|
||||
|
||||
none
|
||||
Do not generate stack canaries.
|
||||
"#
|
||||
);
|
||||
}
|
||||
req => llvm_util::print(req, sess),
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,6 +166,9 @@ pub enum Attribute {
|
||||
InaccessibleMemOnly = 27,
|
||||
SanitizeHWAddress = 28,
|
||||
WillReturn = 29,
|
||||
StackProtectReq = 30,
|
||||
StackProtectStrong = 31,
|
||||
StackProtect = 32,
|
||||
}
|
||||
|
||||
/// LLVMIntPredicate
|
||||
@ -416,6 +419,7 @@ pub enum MetadataType {
|
||||
MD_nontemporal = 9,
|
||||
MD_mem_parallel_loop_access = 10,
|
||||
MD_nonnull = 11,
|
||||
MD_type = 19,
|
||||
}
|
||||
|
||||
/// LLVMRustAsmDialect
|
||||
@ -1002,6 +1006,8 @@ extern "C" {
|
||||
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
|
||||
pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
|
||||
pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
|
||||
pub fn LLVMGlobalSetMetadata(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
|
||||
pub fn LLVMValueAsMetadata(Node: &'a Value) -> &Metadata;
|
||||
|
||||
// Operations on constants of any type
|
||||
pub fn LLVMConstNull(Ty: &Type) -> &Value;
|
||||
@ -1734,6 +1740,8 @@ extern "C" {
|
||||
|
||||
pub fn LLVMTimeTraceProfilerInitialize();
|
||||
|
||||
pub fn LLVMTimeTraceProfilerFinishThread();
|
||||
|
||||
pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char);
|
||||
|
||||
pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>);
|
||||
@ -1770,7 +1778,7 @@ extern "C" {
|
||||
|
||||
pub fn LLVMDisposeMessage(message: *mut c_char);
|
||||
|
||||
pub fn LLVMStartMultithreaded() -> Bool;
|
||||
pub fn LLVMIsMultithreaded() -> Bool;
|
||||
|
||||
/// Returns a string describing the last error caused by an LLVMRust* call.
|
||||
pub fn LLVMRustGetLastError() -> *const c_char;
|
||||
@ -2187,6 +2195,7 @@ extern "C" {
|
||||
UseSoftFP: bool,
|
||||
FunctionSections: bool,
|
||||
DataSections: bool,
|
||||
UniqueSectionNames: bool,
|
||||
TrapUnreachable: bool,
|
||||
Singlethread: bool,
|
||||
AsmComments: bool,
|
||||
|
||||
@ -17,35 +17,25 @@ use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Once;
|
||||
|
||||
static POISONED: AtomicBool = AtomicBool::new(false);
|
||||
static INIT: Once = Once::new();
|
||||
|
||||
pub(crate) fn init(sess: &Session) {
|
||||
unsafe {
|
||||
// Before we touch LLVM, make sure that multithreading is enabled.
|
||||
if llvm::LLVMIsMultithreaded() != 1 {
|
||||
bug!("LLVM compiled without support for threads");
|
||||
}
|
||||
INIT.call_once(|| {
|
||||
if llvm::LLVMStartMultithreaded() != 1 {
|
||||
// use an extra bool to make sure that all future usage of LLVM
|
||||
// cannot proceed despite the Once not running more than once.
|
||||
POISONED.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
configure_llvm(sess);
|
||||
});
|
||||
|
||||
if POISONED.load(Ordering::SeqCst) {
|
||||
bug!("couldn't enable multi-threaded LLVM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn require_inited() {
|
||||
INIT.call_once(|| bug!("llvm is not initialized"));
|
||||
if POISONED.load(Ordering::SeqCst) {
|
||||
bug!("couldn't enable multi-threaded LLVM");
|
||||
if !INIT.is_completed() {
|
||||
bug!("LLVM is not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +75,9 @@ unsafe fn configure_llvm(sess: &Session) {
|
||||
if sess.print_llvm_passes() {
|
||||
add("-debug-pass=Structure", false);
|
||||
}
|
||||
if !sess.opts.debugging_opts.no_generate_arange_section {
|
||||
if sess.target.generate_arange_section
|
||||
&& !sess.opts.debugging_opts.no_generate_arange_section
|
||||
{
|
||||
add("-generate-arange-section", false);
|
||||
}
|
||||
|
||||
@ -95,8 +87,7 @@ unsafe fn configure_llvm(sess: &Session) {
|
||||
// Ref:
|
||||
// - https://github.com/rust-lang/rust/issues/85351
|
||||
// - https://reviews.llvm.org/D103167
|
||||
let llvm_version = llvm_util::get_version();
|
||||
if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) {
|
||||
if llvm_util::get_version() < (13, 0, 0) {
|
||||
add("-enable-machine-outliner=never", false);
|
||||
}
|
||||
|
||||
@ -124,11 +115,6 @@ unsafe fn configure_llvm(sess: &Session) {
|
||||
}
|
||||
|
||||
if sess.opts.debugging_opts.llvm_time_trace {
|
||||
// time-trace is not thread safe and running it in parallel will cause seg faults.
|
||||
if !sess.opts.debugging_opts.no_parallel_llvm {
|
||||
bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm")
|
||||
}
|
||||
|
||||
llvm::LLVMTimeTraceProfilerInitialize();
|
||||
}
|
||||
|
||||
@ -191,6 +177,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> {
|
||||
("aarch64", "dpb2") => vec!["ccdp"],
|
||||
("aarch64", "frintts") => vec!["fptoint"],
|
||||
("aarch64", "fcma") => vec!["complxnum"],
|
||||
("aarch64", "pmuv3") => vec!["perfmon"],
|
||||
(_, s) => vec![s],
|
||||
}
|
||||
}
|
||||
@ -416,14 +403,6 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
|
||||
// -Ctarget-features
|
||||
features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
|
||||
|
||||
// FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12.
|
||||
if get_version() >= (12, 0, 0)
|
||||
&& sess.target.llvm_target.contains("aarch64-unknown-linux")
|
||||
&& sess.target.llvm_target != "aarch64-unknown-linux-musl"
|
||||
{
|
||||
features.push("+outline-atomics".to_string());
|
||||
}
|
||||
|
||||
features
|
||||
}
|
||||
|
||||
|
||||
@ -121,6 +121,19 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
|
||||
if sess.opts.json_artifact_notifications {
|
||||
sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link");
|
||||
}
|
||||
|
||||
if sess.prof.enabled() {
|
||||
if let Some(artifact_name) = out_filename.file_name() {
|
||||
// Record size for self-profiling
|
||||
let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
|
||||
|
||||
sess.prof.artifact_size(
|
||||
"linked_artifact",
|
||||
artifact_name.to_string_lossy(),
|
||||
file_size,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,9 +187,8 @@ pub fn each_linked_rlib(
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let fmts = match fmts {
|
||||
Some(f) => f,
|
||||
None => return Err("could not find formats for rlibs".to_string()),
|
||||
let Some(fmts) = fmts else {
|
||||
return Err("could not find formats for rlibs".to_string());
|
||||
};
|
||||
for &cnum in crates {
|
||||
match fmts.get(cnum.as_usize() - 1) {
|
||||
@ -1022,8 +1034,10 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
||||
SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
|
||||
}
|
||||
|
||||
let strip = strip_value(sess);
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
match sess.opts.debugging_opts.strip {
|
||||
match strip {
|
||||
Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
|
||||
Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None),
|
||||
Strip::None => {}
|
||||
@ -1031,6 +1045,14 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
||||
}
|
||||
}
|
||||
|
||||
// Temporarily support both -Z strip and -C strip
|
||||
fn strip_value(sess: &Session) -> Strip {
|
||||
match (sess.opts.debugging_opts.strip, sess.opts.cg.strip) {
|
||||
(s, Strip::None) => s,
|
||||
(_, s) => s,
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) {
|
||||
let mut cmd = Command::new("strip");
|
||||
if let Some(option) = option {
|
||||
@ -1096,10 +1118,10 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
|
||||
}
|
||||
|
||||
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
|
||||
fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
|
||||
fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
|
||||
let session_tlib =
|
||||
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
|
||||
let path = session_tlib.join(&filename);
|
||||
let path = session_tlib.join(filename);
|
||||
if path.exists() {
|
||||
return session_tlib;
|
||||
} else {
|
||||
@ -2002,7 +2024,7 @@ fn add_order_independent_options(
|
||||
cmd.optimize();
|
||||
|
||||
// Pass debuginfo and strip flags down to the linker.
|
||||
cmd.debuginfo(sess.opts.debugging_opts.strip);
|
||||
cmd.debuginfo(strip_value(sess));
|
||||
|
||||
// We want to prevent the compiler from accidentally leaking in any system libraries,
|
||||
// so by default we tell linkers not to link to any default libraries.
|
||||
|
||||
@ -219,19 +219,36 @@ pub struct GccLinker<'a> {
|
||||
}
|
||||
|
||||
impl<'a> GccLinker<'a> {
|
||||
/// Argument that must be passed *directly* to the linker
|
||||
/// Passes an argument directly to the linker.
|
||||
///
|
||||
/// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
|
||||
fn linker_arg<S>(&mut self, arg: S) -> &mut Self
|
||||
where
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
if !self.is_ld {
|
||||
let mut os = OsString::from("-Wl,");
|
||||
os.push(arg.as_ref());
|
||||
self.cmd.arg(os);
|
||||
/// When the linker is not ld-like such as when using a compiler as a linker, the argument is
|
||||
/// prepended by `-Wl,`.
|
||||
fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
|
||||
self.linker_args(&[arg]);
|
||||
self
|
||||
}
|
||||
|
||||
/// Passes a series of arguments directly to the linker.
|
||||
///
|
||||
/// When the linker is ld-like, the arguments are simply appended to the command. When the
|
||||
/// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
|
||||
/// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
|
||||
/// single argument is appended to the command to ensure that the order of the arguments is
|
||||
/// preserved by the compiler.
|
||||
fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self {
|
||||
if self.is_ld {
|
||||
args.into_iter().for_each(|a| {
|
||||
self.cmd.arg(a);
|
||||
});
|
||||
} else {
|
||||
self.cmd.arg(arg);
|
||||
if !args.is_empty() {
|
||||
let mut s = OsString::from("-Wl");
|
||||
for a in args {
|
||||
s.push(",");
|
||||
s.push(a);
|
||||
}
|
||||
self.cmd.arg(s);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
@ -289,14 +306,19 @@ impl<'a> GccLinker<'a> {
|
||||
if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
|
||||
self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
|
||||
};
|
||||
self.linker_arg(&format!("-plugin-opt={}", opt_level));
|
||||
self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu));
|
||||
self.linker_args(&[
|
||||
&format!("-plugin-opt={}", opt_level),
|
||||
&format!("-plugin-opt=mcpu={}", self.target_cpu),
|
||||
]);
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, out_filename: &Path) {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if self.sess.target.is_like_osx {
|
||||
self.cmd.arg("-dynamiclib");
|
||||
if !self.is_ld {
|
||||
self.cmd.arg("-dynamiclib");
|
||||
}
|
||||
|
||||
self.linker_arg("-dylib");
|
||||
|
||||
// Note that the `osx_rpath_install_name` option here is a hack
|
||||
@ -304,10 +326,9 @@ impl<'a> GccLinker<'a> {
|
||||
// principled solution at some point to force the compiler to pass
|
||||
// the right `-Wl,-install_name` with an `@rpath` in it.
|
||||
if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
|
||||
self.linker_arg("-install_name");
|
||||
let mut v = OsString::from("@rpath/");
|
||||
v.push(out_filename.file_name().unwrap());
|
||||
self.linker_arg(&v);
|
||||
let mut rpath = OsString::from("@rpath/");
|
||||
rpath.push(out_filename.file_name().unwrap());
|
||||
self.linker_args(&[OsString::from("-install_name"), rpath]);
|
||||
}
|
||||
} else {
|
||||
self.cmd.arg("-shared");
|
||||
@ -381,8 +402,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
self.build_dylib(out_filename);
|
||||
}
|
||||
LinkOutputKind::WasiReactorExe => {
|
||||
self.linker_arg("--entry");
|
||||
self.linker_arg("_initialize");
|
||||
self.linker_args(&["--entry", "_initialize"]);
|
||||
}
|
||||
}
|
||||
// VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
|
||||
@ -454,8 +474,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
self.cmd.arg(path);
|
||||
}
|
||||
fn full_relro(&mut self) {
|
||||
self.linker_arg("-zrelro");
|
||||
self.linker_arg("-znow");
|
||||
self.linker_args(&["-zrelro", "-znow"]);
|
||||
}
|
||||
fn partial_relro(&mut self) {
|
||||
self.linker_arg("-zrelro");
|
||||
@ -639,7 +658,6 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
}
|
||||
|
||||
let is_windows = self.sess.target.is_like_windows;
|
||||
let mut arg = OsString::new();
|
||||
let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
|
||||
|
||||
debug!("EXPORTED SYMBOLS:");
|
||||
@ -691,27 +709,18 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
}
|
||||
|
||||
if self.sess.target.is_like_osx {
|
||||
if !self.is_ld {
|
||||
arg.push("-Wl,")
|
||||
}
|
||||
arg.push("-exported_symbols_list,");
|
||||
self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]);
|
||||
} else if self.sess.target.is_like_solaris {
|
||||
if !self.is_ld {
|
||||
arg.push("-Wl,")
|
||||
}
|
||||
arg.push("-M,");
|
||||
self.linker_args(&[OsString::from("-M"), path.into()]);
|
||||
} else {
|
||||
if !self.is_ld {
|
||||
arg.push("-Wl,")
|
||||
}
|
||||
// Both LD and LLD accept export list in *.def file form, there are no flags required
|
||||
if !is_windows {
|
||||
arg.push("--version-script=")
|
||||
if is_windows {
|
||||
self.linker_arg(path);
|
||||
} else {
|
||||
let mut arg = OsString::from("--version-script=");
|
||||
arg.push(path);
|
||||
self.linker_arg(arg);
|
||||
}
|
||||
}
|
||||
|
||||
arg.push(&path);
|
||||
self.cmd.arg(arg);
|
||||
}
|
||||
|
||||
fn subsystem(&mut self, subsystem: &str) {
|
||||
@ -769,8 +778,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||
self.linker_arg("--as-needed");
|
||||
} else if self.sess.target.is_like_solaris {
|
||||
// -z ignore is the Solaris equivalent to the GNU ld --as-needed option
|
||||
self.linker_arg("-z");
|
||||
self.linker_arg("ignore");
|
||||
self.linker_args(&["-z", "ignore"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::middle::exported_symbols::{
|
||||
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
|
||||
};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::query::{ExternProviders, Providers};
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::{SymbolName, TyCtxt};
|
||||
@ -363,7 +363,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
providers.wasm_import_module_map = wasm_import_module_map;
|
||||
}
|
||||
|
||||
pub fn provide_extern(providers: &mut Providers) {
|
||||
pub fn provide_extern(providers: &mut ExternProviders) {
|
||||
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
|
||||
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
|
||||
}
|
||||
|
||||
@ -310,6 +310,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
||||
pub no_landing_pads: bool,
|
||||
pub save_temps: bool,
|
||||
pub fewer_names: bool,
|
||||
pub time_trace: bool,
|
||||
pub exported_symbols: Option<Arc<ExportedSymbols>>,
|
||||
pub opts: Arc<config::Options>,
|
||||
pub crate_types: Vec<CrateType>,
|
||||
@ -1039,6 +1040,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||
no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
|
||||
fewer_names: sess.fewer_names(),
|
||||
save_temps: sess.opts.cg.save_temps,
|
||||
time_trace: sess.opts.debugging_opts.llvm_time_trace,
|
||||
opts: Arc::new(sess.opts.clone()),
|
||||
prof: sess.prof.clone(),
|
||||
exported_symbols,
|
||||
@ -1198,7 +1200,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||
// Each LLVM module is automatically sent back to the coordinator for LTO if
|
||||
// necessary. There's already optimizations in place to avoid sending work
|
||||
// back to the coordinator if LTO isn't requested.
|
||||
return thread::spawn(move || {
|
||||
return B::spawn_thread(cgcx.time_trace, move || {
|
||||
let mut worker_id_counter = 0;
|
||||
let mut free_worker_ids = Vec::new();
|
||||
let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
|
||||
@ -1615,59 +1617,57 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||
pub struct WorkerFatalError;
|
||||
|
||||
fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
|
||||
let builder = thread::Builder::new().name(work.short_description());
|
||||
builder
|
||||
.spawn(move || {
|
||||
// Set up a destructor which will fire off a message that we're done as
|
||||
// we exit.
|
||||
struct Bomb<B: ExtraBackendMethods> {
|
||||
coordinator_send: Sender<Box<dyn Any + Send>>,
|
||||
result: Option<Result<WorkItemResult<B>, FatalError>>,
|
||||
worker_id: usize,
|
||||
}
|
||||
impl<B: ExtraBackendMethods> Drop for Bomb<B> {
|
||||
fn drop(&mut self) {
|
||||
let worker_id = self.worker_id;
|
||||
let msg = match self.result.take() {
|
||||
Some(Ok(WorkItemResult::Compiled(m))) => {
|
||||
Message::Done::<B> { result: Ok(m), worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsLink(m))) => {
|
||||
Message::NeedsLink::<B> { module: m, worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
|
||||
Message::NeedsFatLTO::<B> { result: m, worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
|
||||
Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
|
||||
}
|
||||
Some(Err(FatalError)) => {
|
||||
Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
|
||||
}
|
||||
None => Message::Done::<B> { result: Err(None), worker_id },
|
||||
};
|
||||
drop(self.coordinator_send.send(Box::new(msg)));
|
||||
}
|
||||
B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
|
||||
// Set up a destructor which will fire off a message that we're done as
|
||||
// we exit.
|
||||
struct Bomb<B: ExtraBackendMethods> {
|
||||
coordinator_send: Sender<Box<dyn Any + Send>>,
|
||||
result: Option<Result<WorkItemResult<B>, FatalError>>,
|
||||
worker_id: usize,
|
||||
}
|
||||
impl<B: ExtraBackendMethods> Drop for Bomb<B> {
|
||||
fn drop(&mut self) {
|
||||
let worker_id = self.worker_id;
|
||||
let msg = match self.result.take() {
|
||||
Some(Ok(WorkItemResult::Compiled(m))) => {
|
||||
Message::Done::<B> { result: Ok(m), worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsLink(m))) => {
|
||||
Message::NeedsLink::<B> { module: m, worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
|
||||
Message::NeedsFatLTO::<B> { result: m, worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
|
||||
Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
|
||||
}
|
||||
Some(Err(FatalError)) => {
|
||||
Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
|
||||
}
|
||||
None => Message::Done::<B> { result: Err(None), worker_id },
|
||||
};
|
||||
drop(self.coordinator_send.send(Box::new(msg)));
|
||||
}
|
||||
}
|
||||
|
||||
let mut bomb = Bomb::<B> {
|
||||
coordinator_send: cgcx.coordinator_send.clone(),
|
||||
result: None,
|
||||
worker_id: cgcx.worker,
|
||||
};
|
||||
let mut bomb = Bomb::<B> {
|
||||
coordinator_send: cgcx.coordinator_send.clone(),
|
||||
result: None,
|
||||
worker_id: cgcx.worker,
|
||||
};
|
||||
|
||||
// Execute the work itself, and if it finishes successfully then flag
|
||||
// ourselves as a success as well.
|
||||
//
|
||||
// Note that we ignore any `FatalError` coming out of `execute_work_item`,
|
||||
// as a diagnostic was already sent off to the main thread - just
|
||||
// surface that there was an error in this worker.
|
||||
bomb.result = {
|
||||
let _prof_timer = work.start_profiling(&cgcx);
|
||||
Some(execute_work_item(&cgcx, work))
|
||||
};
|
||||
})
|
||||
.expect("failed to spawn thread");
|
||||
// Execute the work itself, and if it finishes successfully then flag
|
||||
// ourselves as a success as well.
|
||||
//
|
||||
// Note that we ignore any `FatalError` coming out of `execute_work_item`,
|
||||
// as a diagnostic was already sent off to the main thread - just
|
||||
// surface that there was an error in this worker.
|
||||
bomb.result = {
|
||||
let _prof_timer = work.start_profiling(&cgcx);
|
||||
Some(execute_work_item(&cgcx, work))
|
||||
};
|
||||
})
|
||||
.expect("failed to spawn thread");
|
||||
}
|
||||
|
||||
enum SharedEmitterMessage {
|
||||
@ -1757,7 +1757,7 @@ impl SharedEmitterMain {
|
||||
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
|
||||
|
||||
let mut err = match level {
|
||||
Level::Error => sess.struct_err(&msg),
|
||||
Level::Error { lint: false } => sess.struct_err(&msg),
|
||||
Level::Warning => sess.struct_warn(&msg),
|
||||
Level::Note => sess.struct_note_without_error(&msg),
|
||||
_ => bug!("Invalid inline asm diagnostic level"),
|
||||
|
||||
@ -124,10 +124,7 @@ fn push_debuginfo_type_name<'tcx>(
|
||||
// info for MSVC debugger. However, wrapping these types' names in a synthetic type
|
||||
// causes the .natvis engine for WinDbg to fail to display their data, so we opt these
|
||||
// types out to aid debugging in MSVC.
|
||||
let is_slice_or_str = match *inner_type.kind() {
|
||||
ty::Slice(_) | ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
|
||||
|
||||
if !cpp_like_names {
|
||||
output.push('&');
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(let_else)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(nll)]
|
||||
#![feature(associated_type_bounds)]
|
||||
@ -26,7 +27,7 @@ use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::middle::dependency_format::Dependencies;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::query::{ExternProviders, Providers};
|
||||
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
|
||||
use rustc_session::cstore::{self, CrateSource};
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
@ -168,7 +169,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
crate::target_features::provide(providers);
|
||||
}
|
||||
|
||||
pub fn provide_extern(providers: &mut Providers) {
|
||||
pub fn provide_extern(providers: &mut ExternProviders) {
|
||||
crate::back::symbol_export::provide_extern(providers);
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::{sym, Symbol};
|
||||
use rustc_symbol_mangling::typeid_for_fnabi;
|
||||
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
|
||||
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
@ -818,12 +819,43 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
|
||||
}
|
||||
|
||||
let fn_ptr = match (llfn, instance) {
|
||||
(Some(llfn), _) => llfn,
|
||||
(None, Some(instance)) => bx.get_fn_addr(instance),
|
||||
let (is_indirect_call, fn_ptr) = match (llfn, instance) {
|
||||
(Some(llfn), _) => (true, llfn),
|
||||
(None, Some(instance)) => (false, bx.get_fn_addr(instance)),
|
||||
_ => span_bug!(span, "no llfn for call"),
|
||||
};
|
||||
|
||||
// For backends that support CFI using type membership (i.e., testing whether a given
|
||||
// pointer is associated with a type identifier).
|
||||
if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
|
||||
// Emit type metadata and checks.
|
||||
// FIXME(rcvalle): Add support for generalized identifiers.
|
||||
// FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
|
||||
let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
|
||||
let typeid_metadata = bx.typeid_metadata(typeid);
|
||||
|
||||
// Test whether the function pointer is associated with the type identifier.
|
||||
let cond = bx.type_test(fn_ptr, typeid_metadata);
|
||||
let mut bx_pass = bx.build_sibling_block("type_test.pass");
|
||||
let mut bx_fail = bx.build_sibling_block("type_test.fail");
|
||||
bx.cond_br(cond, bx_pass.llbb(), bx_fail.llbb());
|
||||
|
||||
helper.do_call(
|
||||
self,
|
||||
&mut bx_pass,
|
||||
fn_abi,
|
||||
fn_ptr,
|
||||
&llargs,
|
||||
destination.as_ref().map(|&(_, target)| (ret_dest, target)),
|
||||
cleanup,
|
||||
);
|
||||
|
||||
bx_fail.abort();
|
||||
bx_fail.unreachable();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
helper.do_call(
|
||||
self,
|
||||
&mut bx,
|
||||
@ -845,6 +877,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
options: ast::InlineAsmOptions,
|
||||
line_spans: &[Span],
|
||||
destination: Option<mir::BasicBlock>,
|
||||
instance: Instance<'_>,
|
||||
) {
|
||||
let span = terminator.source_info.span;
|
||||
|
||||
@ -898,7 +931,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
bx.codegen_inline_asm(template, &operands, options, line_spans);
|
||||
bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
|
||||
|
||||
if let Some(target) = destination {
|
||||
helper.funclet_br(self, &mut bx, target);
|
||||
@ -947,17 +980,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Goto { target } => {
|
||||
if bb == target {
|
||||
// This is an unconditional branch back to this same basic block. That means we
|
||||
// have something like a `loop {}` statement. LLVM versions before 12.0
|
||||
// miscompile this because they assume forward progress. For older versions
|
||||
// try to handle just this specific case which comes up commonly in practice
|
||||
// (e.g., in embedded code).
|
||||
//
|
||||
// NB: the `sideeffect` currently checks for the LLVM version used internally.
|
||||
bx.sideeffect();
|
||||
}
|
||||
|
||||
helper.funclet_br(self, &mut bx, target);
|
||||
}
|
||||
|
||||
@ -1029,6 +1051,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
options,
|
||||
line_spans,
|
||||
destination,
|
||||
self.instance,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
|
||||
use rustc_symbol_mangling::typeid_for_fnabi;
|
||||
use rustc_target::abi::call::{FnAbi, PassMode};
|
||||
|
||||
use std::iter;
|
||||
@ -244,6 +245,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
for (bb, _) in traversal::reverse_postorder(&mir) {
|
||||
fx.codegen_block(bb);
|
||||
}
|
||||
|
||||
// For backends that support CFI using type membership (i.e., testing whether a given pointer
|
||||
// is associated with a type identifier).
|
||||
if cx.tcx().sess.is_sanitizer_cfi_enabled() {
|
||||
let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
|
||||
bx.type_metadata(llfn, typeid);
|
||||
}
|
||||
}
|
||||
|
||||
/// Produces, for each argument, a `Value` pointing at the
|
||||
|
||||
@ -343,9 +343,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
|
||||
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
|
||||
.ty;
|
||||
|
||||
let (llptr, llextra) = if let OperandValue::Ref(llptr, Some(llextra), _) = self {
|
||||
(llptr, llextra)
|
||||
} else {
|
||||
let OperandValue::Ref(llptr, Some(llextra), _) = self else {
|
||||
bug!("store_unsized called with a sized value")
|
||||
};
|
||||
|
||||
|
||||
@ -125,7 +125,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let count = self.codegen_operand(&mut bx, count).immediate();
|
||||
let pointee_layout = dst_val
|
||||
.layout
|
||||
.pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
|
||||
.pointee_info_at(&bx, rustc_target::abi::Size::ZERO)
|
||||
.expect("Expected pointer");
|
||||
let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes()));
|
||||
|
||||
|
||||
@ -19,6 +19,8 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
("crypto", Some(sym::arm_target_feature)),
|
||||
("aes", Some(sym::arm_target_feature)),
|
||||
("sha2", Some(sym::arm_target_feature)),
|
||||
("i8mm", Some(sym::arm_target_feature)),
|
||||
("dotprod", Some(sym::arm_target_feature)),
|
||||
("v5te", Some(sym::arm_target_feature)),
|
||||
("v6", Some(sym::arm_target_feature)),
|
||||
("v6k", Some(sym::arm_target_feature)),
|
||||
@ -35,7 +37,6 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
("thumb-mode", Some(sym::arm_target_feature)),
|
||||
];
|
||||
|
||||
// Commented features are not available in LLVM 10.0, or have since been renamed
|
||||
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
// FEAT_AdvSimd
|
||||
("neon", Some(sym::aarch64_target_feature)),
|
||||
@ -66,13 +67,13 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
// FEAT_DIT
|
||||
("dit", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_FLAGM
|
||||
// ("flagm", Some(sym::aarch64_target_feature)),
|
||||
("flagm", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_SSBS
|
||||
("ssbs", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_SB
|
||||
("sb", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_PAUTH
|
||||
// ("pauth", Some(sym::aarch64_target_feature)),
|
||||
("pauth", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_DPB
|
||||
("dpb", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_DPB2
|
||||
@ -90,13 +91,13 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
// FEAT_FRINTTS
|
||||
("frintts", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_I8MM
|
||||
// ("i8mm", Some(sym::aarch64_target_feature)),
|
||||
("i8mm", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_F32MM
|
||||
// ("f32mm", Some(sym::aarch64_target_feature)),
|
||||
("f32mm", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_F64MM
|
||||
// ("f64mm", Some(sym::aarch64_target_feature)),
|
||||
("f64mm", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_BF16
|
||||
// ("bf16", Some(sym::aarch64_target_feature)),
|
||||
("bf16", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_RAND
|
||||
("rand", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_BTI
|
||||
@ -115,13 +116,23 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
("sha3", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_SM3 & FEAT_SM4
|
||||
("sm4", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_PAN
|
||||
("pan", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_LOR
|
||||
("lor", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_VHE
|
||||
("vh", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_PMUv3
|
||||
("pmuv3", Some(sym::aarch64_target_feature)),
|
||||
// FEAT_SPE
|
||||
("spe", Some(sym::aarch64_target_feature)),
|
||||
("v8.1a", Some(sym::aarch64_target_feature)),
|
||||
("v8.2a", Some(sym::aarch64_target_feature)),
|
||||
("v8.3a", Some(sym::aarch64_target_feature)),
|
||||
("v8.4a", Some(sym::aarch64_target_feature)),
|
||||
("v8.5a", Some(sym::aarch64_target_feature)),
|
||||
// ("v8.6a", Some(sym::aarch64_target_feature)),
|
||||
// ("v8.7a", Some(sym::aarch64_target_feature)),
|
||||
("v8.6a", Some(sym::aarch64_target_feature)),
|
||||
("v8.7a", Some(sym::aarch64_target_feature)),
|
||||
];
|
||||
|
||||
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
|
||||
@ -4,5 +4,5 @@ use rustc_target::abi::call::FnAbi;
|
||||
|
||||
pub trait AbiBuilderMethods<'tcx>: BackendTypes {
|
||||
fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value);
|
||||
fn get_param(&self, index: usize) -> Self::Value;
|
||||
fn get_param(&mut self, index: usize) -> Self::Value;
|
||||
}
|
||||
|
||||
@ -58,6 +58,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
||||
operands: &[InlineAsmOperandRef<'tcx, Self>],
|
||||
options: InlineAsmOptions,
|
||||
line_spans: &[Span],
|
||||
instance: Instance<'_>,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ use rustc_errors::ErrorReported;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::query::{ExternProviders, Providers};
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_session::{
|
||||
config::{self, OutputFilenames, PrintRequest},
|
||||
@ -80,7 +80,7 @@ pub trait CodegenBackend {
|
||||
}
|
||||
|
||||
fn provide(&self, _providers: &mut Providers) {}
|
||||
fn provide_extern(&self, _providers: &mut Providers) {}
|
||||
fn provide_extern(&self, _providers: &mut ExternProviders) {}
|
||||
fn codegen_crate<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -142,4 +142,26 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
|
||||
) -> TargetMachineFactoryFn<Self>;
|
||||
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
|
||||
fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
|
||||
|
||||
fn spawn_thread<F, T>(_time_trace: bool, f: F) -> std::thread::JoinHandle<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
std::thread::spawn(f)
|
||||
}
|
||||
|
||||
fn spawn_named_thread<F, T>(
|
||||
_time_trace: bool,
|
||||
name: String,
|
||||
f: F,
|
||||
) -> std::io::Result<std::thread::JoinHandle<T>>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
std::thread::Builder::new().name(name).spawn(f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,6 +158,8 @@ pub trait BuilderMethods<'a, 'tcx>:
|
||||
|
||||
fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
|
||||
fn nonnull_metadata(&mut self, load: Self::Value);
|
||||
fn type_metadata(&mut self, function: Self::Function, typeid: String);
|
||||
fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
|
||||
|
||||
fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
|
||||
fn store_with_flags(
|
||||
|
||||
@ -20,10 +20,8 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
|
||||
fn abort(&mut self);
|
||||
fn assume(&mut self, val: Self::Value);
|
||||
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
|
||||
/// Emits a forced side effect.
|
||||
///
|
||||
/// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend.
|
||||
fn sideeffect(&mut self);
|
||||
/// Trait method used to test whether a given pointer is associated with a type identifier.
|
||||
fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value;
|
||||
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
|
||||
/// Rust defined C-variadic functions.
|
||||
fn va_start(&mut self, val: Self::Value) -> Self::Value;
|
||||
|
||||
@ -25,10 +25,7 @@ pub enum ConstEvalErrKind {
|
||||
|
||||
impl MachineStopType for ConstEvalErrKind {
|
||||
fn is_hard_err(&self) -> bool {
|
||||
match self {
|
||||
Self::Panic { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, Self::Panic { .. })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
||||
| DefKind::Static
|
||||
| DefKind::ConstParam
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::AssocConst
|
||||
),
|
||||
"Unexpected DefKind: {:?}",
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::hir::map::blocks::FnLikeNode;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::symbol::Symbol;
|
||||
@ -44,18 +43,16 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if let Some(fn_like) = FnLikeNode::from_node(node) {
|
||||
if fn_like.constness() == hir::Constness::Const {
|
||||
} else if let Some(fn_kind) = node.fn_kind() {
|
||||
if fn_kind.constness() == hir::Constness::Const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the function itself is not annotated with `const`, it may still be a `const fn`
|
||||
// if it resides in a const trait impl.
|
||||
is_parent_const_impl_raw(tcx, hir_id)
|
||||
} else if let hir::Node::Ctor(_) = node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
matches!(node, hir::Node::Ctor(_))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,34 +30,25 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
is_const_fn: bool,
|
||||
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
|
||||
// The list of functions we handle here must be in sync with
|
||||
// `is_lang_special_const_fn` in `transform/check_consts/mod.rs`.
|
||||
// All `#[rustc_do_not_const_check]` functions should be hooked here.
|
||||
let def_id = instance.def_id();
|
||||
|
||||
if is_const_fn {
|
||||
if Some(def_id) == self.tcx.lang_items().const_eval_select() {
|
||||
// redirect to const_eval_select_ct
|
||||
if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
|
||||
return Ok(Some(
|
||||
ty::Instance::resolve(
|
||||
*self.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
const_eval_select,
|
||||
instance.substs,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
));
|
||||
}
|
||||
if Some(def_id) == self.tcx.lang_items().const_eval_select() {
|
||||
// redirect to const_eval_select_ct
|
||||
if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
|
||||
return Ok(Some(
|
||||
ty::Instance::resolve(
|
||||
*self.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
const_eval_select,
|
||||
instance.substs,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
));
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if Some(def_id) == self.tcx.lang_items().panic_fn()
|
||||
|| Some(def_id) == self.tcx.lang_items().panic_str()
|
||||
|| Some(def_id) == self.tcx.lang_items().panic_display()
|
||||
} else if Some(def_id) == self.tcx.lang_items().panic_display()
|
||||
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
|
||||
{
|
||||
// &str or &&str
|
||||
@ -72,9 +63,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
|
||||
let span = self.find_closest_untracked_caller_location();
|
||||
let (file, line, col) = self.location_triple_for_span(span);
|
||||
return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into());
|
||||
} else if Some(def_id) == self.tcx.lang_items().panic_fmt()
|
||||
|| Some(def_id) == self.tcx.lang_items().begin_panic_fmt()
|
||||
{
|
||||
} else if Some(def_id) == self.tcx.lang_items().panic_fmt() {
|
||||
// For panic_fmt, call const_panic_fmt instead.
|
||||
if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() {
|
||||
return Ok(Some(
|
||||
@ -276,31 +265,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
|
||||
// Only check non-glue functions
|
||||
if let ty::InstanceDef::Item(def) = instance.def {
|
||||
let mut is_const_fn = true;
|
||||
|
||||
// Execution might have wandered off into other crates, so we cannot do a stability-
|
||||
// sensitive check here. But we can at least rule out functions that are not const
|
||||
// at all.
|
||||
if !ecx.tcx.is_const_fn_raw(def.did) {
|
||||
// allow calling functions marked with #[default_method_body_is_const].
|
||||
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
|
||||
is_const_fn = false;
|
||||
// We certainly do *not* want to actually call the fn
|
||||
// though, so be sure we return here.
|
||||
throw_unsup_format!("calling non-const function `{}`", instance)
|
||||
}
|
||||
}
|
||||
|
||||
// Some functions we support even if they are non-const -- but avoid testing
|
||||
// that for const fn!
|
||||
// `const_eval_select` is a const fn because it must use const trait bounds.
|
||||
if let Some(new_instance) = ecx.hook_special_const_fn(instance, args, is_const_fn)? {
|
||||
if let Some(new_instance) = ecx.hook_special_const_fn(instance, args)? {
|
||||
// We call another const fn instead.
|
||||
return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind);
|
||||
}
|
||||
|
||||
if !is_const_fn {
|
||||
// We certainly do *not* want to actually call the fn
|
||||
// though, so be sure we return here.
|
||||
throw_unsup_format!("calling non-const function `{}`", instance)
|
||||
}
|
||||
}
|
||||
// This is a const fn. Call it.
|
||||
Ok(Some(ecx.load_mir(instance.def, None)?))
|
||||
|
||||
@ -413,48 +413,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
sym::simd_insert => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let elem = &args[2];
|
||||
let input = &args[0];
|
||||
let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx);
|
||||
let (input, input_len) = self.operand_to_simd(&args[0])?;
|
||||
let (dest, dest_len) = self.place_to_simd(dest)?;
|
||||
assert_eq!(input_len, dest_len, "Return vector length must match input length");
|
||||
assert!(
|
||||
index < len,
|
||||
"Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
|
||||
index < dest_len,
|
||||
"Index `{}` must be in bounds of vector with length {}`",
|
||||
index,
|
||||
e_ty,
|
||||
len
|
||||
);
|
||||
assert_eq!(
|
||||
input.layout, dest.layout,
|
||||
"Return type `{}` must match vector type `{}`",
|
||||
dest.layout.ty, input.layout.ty
|
||||
);
|
||||
assert_eq!(
|
||||
elem.layout.ty, e_ty,
|
||||
"Scalar element type `{}` must match vector element type `{}`",
|
||||
elem.layout.ty, e_ty
|
||||
dest_len
|
||||
);
|
||||
|
||||
for i in 0..len {
|
||||
let place = self.place_index(dest, i)?;
|
||||
let value = if i == index { *elem } else { self.operand_index(input, i)? };
|
||||
self.copy_op(&value, &place)?;
|
||||
for i in 0..dest_len {
|
||||
let place = self.mplace_index(&dest, i)?;
|
||||
let value =
|
||||
if i == index { *elem } else { self.mplace_index(&input, i)?.into() };
|
||||
self.copy_op(&value, &place.into())?;
|
||||
}
|
||||
}
|
||||
sym::simd_extract => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
|
||||
let (input, input_len) = self.operand_to_simd(&args[0])?;
|
||||
assert!(
|
||||
index < len,
|
||||
"index `{}` is out-of-bounds of vector type `{}` with length `{}`",
|
||||
index < input_len,
|
||||
"index `{}` must be in bounds of vector with length `{}`",
|
||||
index,
|
||||
e_ty,
|
||||
len
|
||||
input_len
|
||||
);
|
||||
assert_eq!(
|
||||
e_ty, dest.layout.ty,
|
||||
"Return type `{}` must match vector element type `{}`",
|
||||
dest.layout.ty, e_ty
|
||||
);
|
||||
self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
|
||||
self.copy_op(&self.mplace_index(&input, index)?.into(), dest)?;
|
||||
}
|
||||
sym::likely | sym::unlikely | sym::black_box => {
|
||||
// These just return their argument
|
||||
|
||||
@ -80,10 +80,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
line: u32,
|
||||
col: u32,
|
||||
) -> MPlaceTy<'tcx, M::PointerTag> {
|
||||
let file =
|
||||
self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
|
||||
let line = Scalar::from_u32(line);
|
||||
let col = Scalar::from_u32(col);
|
||||
let loc_details = &self.tcx.sess.opts.debugging_opts.location_detail;
|
||||
let file = if loc_details.file {
|
||||
self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
|
||||
} else {
|
||||
// FIXME: This creates a new allocation each time. It might be preferable to
|
||||
// perform this allocation only once, and re-use the `MPlaceTy`.
|
||||
// See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
|
||||
self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
|
||||
};
|
||||
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
|
||||
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
|
||||
|
||||
// Allocate memory for `CallerLocation` struct.
|
||||
let loc_ty = self
|
||||
|
||||
@ -138,10 +138,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
|
||||
args: &[GenericArg<'tcx>],
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
self = print_prefix(self)?;
|
||||
let args = args.iter().cloned().filter(|arg| match arg.unpack() {
|
||||
GenericArgKind::Lifetime(_) => false,
|
||||
_ => true,
|
||||
});
|
||||
let args =
|
||||
args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
|
||||
if args.clone().next().is_some() {
|
||||
self.generic_delimiters(|cx| cx.comma_sep(args))
|
||||
} else {
|
||||
|
||||
@ -131,6 +131,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
/// Whether to enforce the validity invariant
|
||||
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
|
||||
|
||||
/// Whether to enforce validity (e.g., initialization and not having ptr provenance)
|
||||
/// of integers and floats.
|
||||
fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
|
||||
|
||||
/// Whether function calls should be [ABI](Abi)-checked.
|
||||
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
true
|
||||
@ -426,6 +430,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||
false // for now, we don't enforce validity
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn call_extra_fn(
|
||||
_ecx: &mut InterpCx<$mir, $tcx, Self>,
|
||||
|
||||
@ -1057,20 +1057,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||
Some(dest_ptr) => dest_ptr,
|
||||
};
|
||||
|
||||
// first copy the relocations to a temporary buffer, because
|
||||
// `get_bytes_mut` will clear the relocations, which is correct,
|
||||
// since we don't want to keep any relocations at the target.
|
||||
// (`get_bytes_with_uninit_and_ptr` below checks that there are no
|
||||
// relocations overlapping the edges; those would not be handled correctly).
|
||||
let relocations =
|
||||
src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies);
|
||||
// Prepare a copy of the initialization mask.
|
||||
let compressed = src_alloc.compress_uninit_range(src_range);
|
||||
// This checks relocation edges on the src.
|
||||
// This checks relocation edges on the src, which needs to happen before
|
||||
// `prepare_relocation_copy`.
|
||||
let src_bytes = src_alloc
|
||||
.get_bytes_with_uninit_and_ptr(&tcx, src_range)
|
||||
.map_err(|e| e.to_interp_error(src_alloc_id))?
|
||||
.as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
|
||||
// first copy the relocations to a temporary buffer, because
|
||||
// `get_bytes_mut` will clear the relocations, which is correct,
|
||||
// since we don't want to keep any relocations at the target.
|
||||
let relocations =
|
||||
src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies);
|
||||
// Prepare a copy of the initialization mask.
|
||||
let compressed = src_alloc.compress_uninit_range(src_range);
|
||||
|
||||
// Destination alloc preparations and access hooks.
|
||||
let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?;
|
||||
|
||||
@ -437,6 +437,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements.
|
||||
/// Also returns the number of elements.
|
||||
pub fn operand_to_simd(
|
||||
&self,
|
||||
base: &OpTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
|
||||
// Basically we just transmute this place into an array following simd_size_and_type.
|
||||
// This only works in memory, but repr(simd) types should never be immediates anyway.
|
||||
assert!(base.layout.ty.is_simd());
|
||||
self.mplace_to_simd(&base.assert_mem_place())
|
||||
}
|
||||
|
||||
/// Read from a local. Will not actually access the local if reading from a ZST.
|
||||
/// Will not access memory, instead an indirect `Operand` is returned.
|
||||
///
|
||||
|
||||
@ -130,7 +130,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let signed = left_layout.abi.is_signed();
|
||||
let size = u128::from(left_layout.size.bits());
|
||||
let overflow = r >= size;
|
||||
let r = r % size; // mask to type size
|
||||
// The shift offset is implicitly masked to the type size, to make sure this operation
|
||||
// is always defined. This is the one MIR operator that does *not* directly map to a
|
||||
// single LLVM operation. See
|
||||
// <https://github.com/rust-lang/rust/blob/a3b9405ae7bb6ab4e8103b414e75c44598a10fd2/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
|
||||
// for the corresponding truncation in our codegen backends.
|
||||
let r = r % size;
|
||||
let r = u32::try_from(r).unwrap(); // we masked so this will always fit
|
||||
let result = if signed {
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user