mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-13 18:43:19 +00:00
New upstream version 1.61.0+dfsg1
This commit is contained in:
parent
5099ac242f
commit
5e7ed085d1
129
Cargo.lock
generated
129
Cargo.lock
generated
@ -154,16 +154,16 @@ version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.1.19",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@ -214,14 +214,12 @@ dependencies = [
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper",
|
||||
"cc",
|
||||
"cmake",
|
||||
"filetime",
|
||||
"getopts",
|
||||
"ignore",
|
||||
"libc",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"opener",
|
||||
"pretty_assertions",
|
||||
@ -249,7 +247,6 @@ dependencies = [
|
||||
"anyhow",
|
||||
"flate2",
|
||||
"hex 0.4.2",
|
||||
"num_cpus",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -258,10 +255,6 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build_helper"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "bump-stage0"
|
||||
version = "0.1.0"
|
||||
@ -318,7 +311,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo"
|
||||
version = "0.61.0"
|
||||
version = "0.62.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atty",
|
||||
@ -327,7 +320,7 @@ dependencies = [
|
||||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
"clap 3.1.5",
|
||||
"clap 3.1.1",
|
||||
"crates-io",
|
||||
"crossbeam-utils",
|
||||
"curl",
|
||||
@ -344,7 +337,7 @@ dependencies = [
|
||||
"humantime 2.0.1",
|
||||
"ignore",
|
||||
"im-rc",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
@ -352,7 +345,6 @@ dependencies = [
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
"memchr",
|
||||
"num_cpus",
|
||||
"opener",
|
||||
"openssl",
|
||||
"os_info",
|
||||
@ -449,7 +441,7 @@ dependencies = [
|
||||
"flate2",
|
||||
"git2",
|
||||
"glob",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"remove_dir_all",
|
||||
"serde_json",
|
||||
@ -523,9 +515,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chalk-derive"
|
||||
version = "0.76.0"
|
||||
version = "0.80.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58c24b8052ea1e3adbb6f9ab7ba5fcc18b9d12591c042de4c833f709ce81e0e0"
|
||||
checksum = "d0001adf0cf12361e08b65e1898ea138f8f77d8f5177cbf29b6b3b3532252bd6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -535,9 +527,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chalk-engine"
|
||||
version = "0.76.0"
|
||||
version = "0.80.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eca186b6ea9af798312f4b568fd094c82e7946ac08be5dc5fea22decc6d2ed8"
|
||||
checksum = "c44ee96f2d67cb5193d1503f185db1abad9933a1c6e6b4169c176f90baecd393"
|
||||
dependencies = [
|
||||
"chalk-derive",
|
||||
"chalk-ir",
|
||||
@ -548,9 +540,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chalk-ir"
|
||||
version = "0.76.0"
|
||||
version = "0.80.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cad5c3f1edd4b4a2c9bda24ae558ceb4f88336f88f944c2e35d0bfeb13c818"
|
||||
checksum = "92d8a95548f23618fda86426e4304e563ec2bb7ba0216139f0748d63c107b5f1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chalk-derive",
|
||||
@ -559,15 +551,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chalk-solve"
|
||||
version = "0.76.0"
|
||||
version = "0.80.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94533188d3452bc72cbd5618d166f45fc7646b674ad3fe9667d557bc25236dee"
|
||||
checksum = "f37f492dacfafe2e21319b80827da2779932909bb392f0cc86b2bd5c07c1b4e1"
|
||||
dependencies = [
|
||||
"chalk-derive",
|
||||
"chalk-ir",
|
||||
"ena",
|
||||
"indexmap",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"petgraph",
|
||||
"rustc-hash",
|
||||
"tracing",
|
||||
@ -606,9 +598,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.1.5"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312"
|
||||
checksum = "6d76c22c9b9b215eeb8d016ad3a90417bd13cb24cf8142756e6472445876cab7"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@ -616,12 +608,12 @@ dependencies = [
|
||||
"os_str_bytes",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"textwrap 0.15.0",
|
||||
"textwrap 0.14.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.60"
|
||||
version = "0.1.61"
|
||||
dependencies = [
|
||||
"cargo_metadata",
|
||||
"clippy_lints",
|
||||
@ -631,10 +623,11 @@ dependencies = [
|
||||
"filetime",
|
||||
"futures 0.3.19",
|
||||
"if_chain",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"parking_lot",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-semver",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_tools_util 0.2.0",
|
||||
"semver",
|
||||
@ -653,7 +646,7 @@ dependencies = [
|
||||
"cargo_metadata",
|
||||
"clap 2.34.0",
|
||||
"indoc",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"opener",
|
||||
"regex",
|
||||
"shell-escape",
|
||||
@ -662,12 +655,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.60"
|
||||
version = "0.1.61"
|
||||
dependencies = [
|
||||
"cargo_metadata",
|
||||
"clippy_utils",
|
||||
"if_chain",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"pulldown-cmark",
|
||||
"quine-mc_cluskey",
|
||||
"regex-syntax",
|
||||
@ -683,7 +676,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.60"
|
||||
version = "0.1.61"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"if_chain",
|
||||
@ -1509,9 +1502,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.13.23"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700"
|
||||
checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@ -1524,9 +1517,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git2-curl"
|
||||
version = "0.14.1"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50"
|
||||
checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13"
|
||||
dependencies = [
|
||||
"curl",
|
||||
"git2",
|
||||
@ -1610,6 +1603,15 @@ name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
@ -1780,15 +1782,6 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.1"
|
||||
@ -1981,9 +1974,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.12.24+1.3.0"
|
||||
version = "0.13.2+1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c"
|
||||
checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -2279,9 +2272,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "minifier"
|
||||
version = "0.0.42"
|
||||
version = "0.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55a1388517eda8a68875243b650c26997e055a33d82571b5a0349129faef7d99"
|
||||
checksum = "d81352bda6f4d04af1720afaa762054f66e16caffd93c1f86461a1c0ac4e695e"
|
||||
dependencies = [
|
||||
"macro-utils",
|
||||
]
|
||||
@ -2334,7 +2327,6 @@ dependencies = [
|
||||
"compiletest_rs",
|
||||
"env_logger 0.9.0",
|
||||
"getrandom 0.2.0",
|
||||
"hex 0.4.2",
|
||||
"libc",
|
||||
"log",
|
||||
"measureme 9.1.2",
|
||||
@ -2396,7 +2388,7 @@ version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.1.19",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -2901,9 +2893,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "racer"
|
||||
version = "2.2.0"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0b4b5faaf07040474e8af74a9e19ff167d5d204df5db5c5c765edecfb900358"
|
||||
checksum = "e92c370d4ede487c4d56c8104d1d425cd447db29fe4a668b0f368a46fa9a5861"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap 2.34.0",
|
||||
@ -3135,7 +3127,7 @@ dependencies = [
|
||||
"futures 0.3.19",
|
||||
"heck",
|
||||
"home",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"jsonrpc-core",
|
||||
"lazy_static",
|
||||
"log",
|
||||
@ -3177,7 +3169,7 @@ dependencies = [
|
||||
"derive-new",
|
||||
"env_logger 0.9.0",
|
||||
"fst",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"json",
|
||||
"lazy_static",
|
||||
"log",
|
||||
@ -3408,7 +3400,7 @@ dependencies = [
|
||||
name = "rustc_ast_passes"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr",
|
||||
@ -3451,7 +3443,7 @@ name = "rustc_borrowck"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"polonius-engine",
|
||||
"rustc_const_eval",
|
||||
"rustc_data_structures",
|
||||
@ -3515,6 +3507,7 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_llvm",
|
||||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
@ -3532,7 +3525,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object 0.28.1",
|
||||
@ -3845,7 +3838,6 @@ dependencies = [
|
||||
name = "rustc_lint"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"if_chain",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr",
|
||||
@ -3872,6 +3864,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_hir",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"rustc_span",
|
||||
@ -3882,7 +3875,6 @@ dependencies = [
|
||||
name = "rustc_llvm"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper",
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
@ -4016,7 +4008,7 @@ name = "rustc_mir_transform"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"coverage_test_macros",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_const_eval",
|
||||
@ -4231,7 +4223,6 @@ name = "rustc_session"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"getopts",
|
||||
"num_cpus",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
@ -4417,7 +4408,7 @@ dependencies = [
|
||||
"askama",
|
||||
"atty",
|
||||
"expect-test",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"minifier",
|
||||
"pulldown-cmark",
|
||||
"rayon",
|
||||
@ -4499,7 +4490,7 @@ dependencies = [
|
||||
"env_logger 0.8.4",
|
||||
"getopts",
|
||||
"ignore",
|
||||
"itertools 0.9.0",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"regex",
|
||||
@ -4782,7 +4773,7 @@ dependencies = [
|
||||
"dlmalloc",
|
||||
"fortanix-sgx-abi",
|
||||
"hashbrown 0.12.0",
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.2.0",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object 0.26.2",
|
||||
@ -5032,9 +5023,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
@ -5179,7 +5170,7 @@ checksum = "744e9ed5b352340aa47ce033716991b5589e23781acb97cad37d4ea70560f55b"
|
||||
dependencies = [
|
||||
"combine",
|
||||
"indexmap",
|
||||
"itertools 0.10.1",
|
||||
"itertools",
|
||||
"kstring",
|
||||
"serde",
|
||||
]
|
||||
|
@ -1,4 +1,5 @@
|
||||
[workspace]
|
||||
default-members = ["src/bootstrap"]
|
||||
members = [
|
||||
"src/bootstrap",
|
||||
"compiler/rustc",
|
||||
|
126
RELEASES.md
126
RELEASES.md
@ -1,3 +1,129 @@
|
||||
Version 1.61.0 (2022-05-19)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
|
||||
- [`const fn` signatures can now include generic trait bounds][93827]
|
||||
- [`const fn` signatures can now use `impl Trait` in argument and return position][93827]
|
||||
- [Function pointers can now be created, cast, and passed around in a `const fn`][93827]
|
||||
- [Recursive calls can now set the value of a function's opaque `impl Trait` return type][94081]
|
||||
|
||||
Compiler
|
||||
--------
|
||||
|
||||
- [Linking modifier syntax in `#[link]` attributes and on the command line, as well as the `whole-archive` modifier specifically, are now supported][93901]
|
||||
- [The `char` type is now described as UTF-32 in debuginfo][89887]
|
||||
- The [`#[target_feature]`][target_feature] attribute [can now be used with aarch64 features][90621]
|
||||
- X86 [`#[target_feature = "adx"]` is now stable][93745]
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [`ManuallyDrop<T>` is now documented to have the same layout as `T`][88375]
|
||||
- [`#[ignore = "…"]` messages are printed when running tests][92714]
|
||||
- [Consistently show absent stdio handles on Windows as NULL handles][93263]
|
||||
- [Make `std::io::stdio::lock()` return `'static` handles.][93965] Previously, the creation of locked handles to stdin/stdout/stderr would borrow the handles being locked, which prevented writing `let out = std::io::stdout().lock();` because `out` would outlive the return value of `stdout()`. Such code now works, eliminating a common pitfall that affected many Rust users.
|
||||
- [`Vec::from_raw_parts` is now less restrictive about its inputs][95016]
|
||||
- [`std::thread::available_parallelism` now takes cgroup quotas into account.][92697] Since `available_parallelism` is often used to create a thread pool for parallel computation, which may be CPU-bound for performance, `available_parallelism` will return a value consistent with the ability to use that many threads continuously, if possible. For instance, in a container with 8 virtual CPUs but quotas only allowing for 50% usage, `available_parallelism` will return 4.
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`Pin::static_mut`]
|
||||
- [`Pin::static_ref`]
|
||||
- [`Vec::retain_mut`]
|
||||
- [`VecDeque::retain_mut`]
|
||||
- [`Write` for `Cursor<[u8; N]>`][cursor-write-array]
|
||||
- [`std::os::unix::net::SocketAddr::from_pathname`]
|
||||
- [`std::process::ExitCode`] and [`std::process::Termination`]. The stabilization of these two APIs now makes it possible for programs to return errors from `main` with custom exit codes.
|
||||
- [`std::thread::JoinHandle::is_finished`]
|
||||
|
||||
These APIs are now usable in const contexts:
|
||||
|
||||
- [`<*const T>::offset` and `<*mut T>::offset`][ptr-offset]
|
||||
- [`<*const T>::wrapping_offset` and `<*mut T>::wrapping_offset`][ptr-wrapping_offset]
|
||||
- [`<*const T>::add` and `<*mut T>::add`][ptr-add]
|
||||
- [`<*const T>::sub` and `<*mut T>::sub`][ptr-sub]
|
||||
- [`<*const T>::wrapping_add` and `<*mut T>::wrapping_add`][ptr-wrapping_add]
|
||||
- [`<*const T>::wrapping_sub` and `<*mut T>::wrapping_sub`][ptr-wrapping_sub]
|
||||
- [`<[T]>::as_mut_ptr`][slice-as_mut_ptr]
|
||||
- [`<[T]>::as_ptr_range`][slice-as_ptr_range]
|
||||
- [`<[T]>::as_mut_ptr_range`][slice-as_mut_ptr_range]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
No feature changes, but see compatibility notes.
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- Previously native static libraries were linked as `whole-archive` in some cases, but now rustc tries not to use `whole-archive` unless explicitly requested. This [change][93901] may result in linking errors in some cases. To fix such errors, native libraries linked from the command line, build scripts, or [`#[link]` attributes][link-attr] need to
|
||||
- (more common) either be reordered to respect dependencies between them (if `a` depends on `b` then `a` should go first and `b` second)
|
||||
- (less common) or be updated to use the [`+whole-archive`] modifier.
|
||||
- [Catching a second unwind from FFI code while cleaning up from a Rust panic now causes the process to abort][92911]
|
||||
- [Proc macros no longer see `ident` matchers wrapped in groups][92472]
|
||||
- [The number of `#` in `r#` raw string literals is now required to be less than 256][95251]
|
||||
- [When checking that a dyn type satisfies a trait bound, supertrait bounds are now enforced][92285]
|
||||
- [`cargo vendor` now only accepts one value for each `--sync` flag][cargo/10448]
|
||||
- [`cfg` predicates in `all()` and `any()` are always evaluated to detect errors, instead of short-circuiting.][94295] The compatibility considerations here arise in nightly-only code that used the short-circuiting behavior of `all` to write something like `cfg(all(feature = "nightly", syntax-requiring-nightly))`, which will now fail to compile. Instead, use either `cfg_attr(feature = "nightly", ...)` or nested uses of `cfg`.
|
||||
- [bootstrap: static-libstdcpp is now enabled by default, and can now be disabled when llvm-tools is enabled][94832]
|
||||
|
||||
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.
|
||||
|
||||
- [debuginfo: Refactor debuginfo generation for types][94261]
|
||||
- [Remove the everybody loops pass][93913]
|
||||
|
||||
[88375]: https://github.com/rust-lang/rust/pull/88375/
|
||||
[89887]: https://github.com/rust-lang/rust/pull/89887/
|
||||
[90621]: https://github.com/rust-lang/rust/pull/90621/
|
||||
[92285]: https://github.com/rust-lang/rust/pull/92285/
|
||||
[92472]: https://github.com/rust-lang/rust/pull/92472/
|
||||
[92697]: https://github.com/rust-lang/rust/pull/92697/
|
||||
[92714]: https://github.com/rust-lang/rust/pull/92714/
|
||||
[92911]: https://github.com/rust-lang/rust/pull/92911/
|
||||
[93263]: https://github.com/rust-lang/rust/pull/93263/
|
||||
[93745]: https://github.com/rust-lang/rust/pull/93745/
|
||||
[93827]: https://github.com/rust-lang/rust/pull/93827/
|
||||
[93901]: https://github.com/rust-lang/rust/pull/93901/
|
||||
[93913]: https://github.com/rust-lang/rust/pull/93913/
|
||||
[93965]: https://github.com/rust-lang/rust/pull/93965/
|
||||
[94081]: https://github.com/rust-lang/rust/pull/94081/
|
||||
[94261]: https://github.com/rust-lang/rust/pull/94261/
|
||||
[94295]: https://github.com/rust-lang/rust/pull/94295/
|
||||
[94832]: https://github.com/rust-lang/rust/pull/94832/
|
||||
[95016]: https://github.com/rust-lang/rust/pull/95016/
|
||||
[95251]: https://github.com/rust-lang/rust/pull/95251/
|
||||
[`+whole-archive`]: https://doc.rust-lang.org/stable/rustc/command-line-arguments.html#linking-modifiers-whole-archive
|
||||
[`Pin::static_mut`]: https://doc.rust-lang.org/stable/std/pin/struct.Pin.html#method.static_mut
|
||||
[`Pin::static_ref`]: https://doc.rust-lang.org/stable/std/pin/struct.Pin.html#method.static_ref
|
||||
[`Vec::retain_mut`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.retain_mut
|
||||
[`VecDeque::retain_mut`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.retain_mut
|
||||
[`std::os::unix::net::SocketAddr::from_pathname`]: https://doc.rust-lang.org/stable/std/os/unix/net/struct.SocketAddr.html#method.from_pathname
|
||||
[`std::process::ExitCode`]: https://doc.rust-lang.org/stable/std/process/struct.ExitCode.html
|
||||
[`std::process::Termination`]: https://doc.rust-lang.org/stable/std/process/trait.Termination.html
|
||||
[`std::thread::JoinHandle::is_finished`]: https://doc.rust-lang.org/stable/std/thread/struct.JoinHandle.html#method.is_finished
|
||||
[cargo/10448]: https://github.com/rust-lang/cargo/pull/10448/
|
||||
[cursor-write-array]: https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#impl-Write-4
|
||||
[link-attr]: https://doc.rust-lang.org/stable/reference/items/external-blocks.html#the-link-attribute
|
||||
[ptr-add]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.add
|
||||
[ptr-offset]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
|
||||
[ptr-sub]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.sub
|
||||
[ptr-wrapping_add]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_add
|
||||
[ptr-wrapping_offset]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_offset
|
||||
[ptr-wrapping_sub]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_sub
|
||||
[slice-as_mut_ptr]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_ptr
|
||||
[slice-as_mut_ptr_range]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_ptr_range
|
||||
[slice-as_ptr_range]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_ptr_range
|
||||
[target_feature]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute
|
||||
|
||||
|
||||
Version 1.60.0 (2022-04-07)
|
||||
==========================
|
||||
|
||||
|
@ -19,3 +19,4 @@ features = ['unprefixed_malloc_on_supported_platforms']
|
||||
jemalloc = ['tikv-jemalloc-sys']
|
||||
llvm = ['rustc_driver/llvm']
|
||||
max_level_info = ['rustc_driver/max_level_info']
|
||||
rustc_use_parallel_compiler = ['rustc_driver/rustc_use_parallel_compiler']
|
||||
|
@ -461,7 +461,7 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> {
|
||||
(combined / 10) as u32 as Limb
|
||||
});
|
||||
|
||||
// Reduce the sigificand to avoid wasting time dividing 0's.
|
||||
// Reduce the significand to avoid wasting time dividing 0's.
|
||||
while sig.last() == Some(&0) {
|
||||
sig.pop();
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#![feature(decl_macro)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![feature(strict_provenance)]
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@ -87,7 +88,7 @@ impl<T> ArenaChunk<T> {
|
||||
unsafe {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// A pointer as large as possible for zero-sized elements.
|
||||
!0 as *mut T
|
||||
ptr::invalid_mut(!0)
|
||||
} else {
|
||||
self.start().add(self.storage.len())
|
||||
}
|
||||
@ -199,7 +200,7 @@ impl<T> TypedArena<T> {
|
||||
unsafe {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
|
||||
let ptr = mem::align_of::<T>() as *mut T;
|
||||
let ptr = ptr::NonNull::<T>::dangling().as_ptr();
|
||||
// Don't drop the object. This `write` is equivalent to `forget`.
|
||||
ptr::write(ptr, object);
|
||||
&mut *ptr
|
||||
@ -216,7 +217,9 @@ impl<T> TypedArena<T> {
|
||||
|
||||
#[inline]
|
||||
fn can_allocate(&self, additional: usize) -> bool {
|
||||
let available_bytes = self.end.get() as usize - self.ptr.get() as usize;
|
||||
// FIXME: this should *likely* use `offset_from`, but more
|
||||
// investigation is needed (including running tests in miri).
|
||||
let available_bytes = self.end.get().addr() - self.ptr.get().addr();
|
||||
let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap();
|
||||
available_bytes >= additional_bytes
|
||||
}
|
||||
@ -262,7 +265,9 @@ impl<T> TypedArena<T> {
|
||||
// If a type is `!needs_drop`, we don't need to keep track of how many elements
|
||||
// the chunk stores - the field will be ignored anyway.
|
||||
if mem::needs_drop::<T>() {
|
||||
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
|
||||
// FIXME: this should *likely* use `offset_from`, but more
|
||||
// investigation is needed (including running tests in miri).
|
||||
let used_bytes = self.ptr.get().addr() - last_chunk.start().addr();
|
||||
last_chunk.entries = used_bytes / mem::size_of::<T>();
|
||||
}
|
||||
|
||||
@ -288,9 +293,9 @@ impl<T> TypedArena<T> {
|
||||
// chunks.
|
||||
fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk<T>) {
|
||||
// Determine how much was filled.
|
||||
let start = last_chunk.start() as usize;
|
||||
let start = last_chunk.start().addr();
|
||||
// We obtain the value of the pointer to the first uninitialized element.
|
||||
let end = self.ptr.get() as usize;
|
||||
let end = self.ptr.get().addr();
|
||||
// We then calculate the number of elements to be dropped in the last chunk,
|
||||
// which is the filled area's length.
|
||||
let diff = if mem::size_of::<T>() == 0 {
|
||||
@ -299,6 +304,8 @@ impl<T> TypedArena<T> {
|
||||
// Recall that `end` was incremented for each allocated value.
|
||||
end - start
|
||||
} else {
|
||||
// FIXME: this should *likely* use `offset_from`, but more
|
||||
// investigation is needed (including running tests in miri).
|
||||
(end - start) / mem::size_of::<T>()
|
||||
};
|
||||
// Pass that to the `destroy` method.
|
||||
@ -395,15 +402,16 @@ impl DroplessArena {
|
||||
/// request.
|
||||
#[inline]
|
||||
fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
|
||||
let start = self.start.get() as usize;
|
||||
let end = self.end.get() as usize;
|
||||
let start = self.start.get().addr();
|
||||
let old_end = self.end.get();
|
||||
let end = old_end.addr();
|
||||
|
||||
let align = layout.align();
|
||||
let bytes = layout.size();
|
||||
|
||||
let new_end = end.checked_sub(bytes)? & !(align - 1);
|
||||
if start <= new_end {
|
||||
let new_end = new_end as *mut u8;
|
||||
let new_end = old_end.with_addr(new_end);
|
||||
self.end.set(new_end);
|
||||
Some(new_end)
|
||||
} else {
|
||||
|
@ -285,7 +285,7 @@ impl ParenthesizedArgs {
|
||||
|
||||
pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
|
||||
|
||||
/// A modifier on a bound, e.g., `?Sized` or `~const Trait`.
|
||||
/// A modifier on a bound, e.g., `?Trait` or `~const Trait`.
|
||||
///
|
||||
/// Negative bounds should also be handled here.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
@ -510,7 +510,7 @@ pub struct WhereEqPredicate {
|
||||
pub struct Crate {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub items: Vec<P<Item>>,
|
||||
pub span: Span,
|
||||
pub spans: ModSpans,
|
||||
/// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold
|
||||
/// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that.
|
||||
pub id: NodeId,
|
||||
@ -1616,7 +1616,7 @@ pub enum StrStyle {
|
||||
/// A raw string, like `r##"foo"##`.
|
||||
///
|
||||
/// The value is the number of `#` symbols used.
|
||||
Raw(u16),
|
||||
Raw(u8),
|
||||
}
|
||||
|
||||
/// An AST literal.
|
||||
@ -2317,11 +2317,25 @@ pub enum ModKind {
|
||||
/// or with definition outlined to a separate file `mod foo;` and already loaded from it.
|
||||
/// The inner span is from the first token past `{` to the last token until `}`,
|
||||
/// or from the first to the last token in the loaded file.
|
||||
Loaded(Vec<P<Item>>, Inline, Span),
|
||||
Loaded(Vec<P<Item>>, Inline, ModSpans),
|
||||
/// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
|
||||
Unloaded,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||
pub struct ModSpans {
|
||||
/// `inner_span` covers the body of the module; for a file module, its the whole file.
|
||||
/// For an inline module, its the span inside the `{ ... }`, not including the curly braces.
|
||||
pub inner_span: Span,
|
||||
pub inject_use_span: Span,
|
||||
}
|
||||
|
||||
impl Default for ModSpans {
|
||||
fn default() -> ModSpans {
|
||||
ModSpans { inner_span: Default::default(), inject_use_span: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Foreign module declaration.
|
||||
///
|
||||
/// E.g., `extern { .. }` or `extern "C" { .. }`.
|
||||
@ -2418,8 +2432,7 @@ impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId {
|
||||
}
|
||||
|
||||
impl<D: Decoder> rustc_serialize::Decodable<D> for AttrId {
|
||||
fn decode(d: &mut D) -> AttrId {
|
||||
d.read_unit();
|
||||
fn decode(_: &mut D) -> AttrId {
|
||||
crate::attr::mk_attr_id()
|
||||
}
|
||||
}
|
||||
@ -2663,10 +2676,37 @@ pub struct Trait {
|
||||
pub items: Vec<P<AssocItem>>,
|
||||
}
|
||||
|
||||
/// The location of a where clause on a `TyAlias` (`Span`) and whether there was
|
||||
/// a `where` keyword (`bool`). This is split out from `WhereClause`, since there
|
||||
/// are two locations for where clause on type aliases, but their predicates
|
||||
/// are concatenated together.
|
||||
///
|
||||
/// Take this example:
|
||||
/// ```ignore (only-for-syntax-highlight)
|
||||
/// trait Foo {
|
||||
/// type Assoc<'a, 'b> where Self: 'a, Self: 'b;
|
||||
/// }
|
||||
/// impl Foo for () {
|
||||
/// type Assoc<'a, 'b> where Self: 'a = () where Self: 'b;
|
||||
/// // ^^^^^^^^^^^^^^ first where clause
|
||||
/// // ^^^^^^^^^^^^^^ second where clause
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If there is no where clause, then this is `false` with `DUMMY_SP`.
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
|
||||
pub struct TyAliasWhereClause(pub bool, pub Span);
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct TyAlias {
|
||||
pub defaultness: Defaultness,
|
||||
pub generics: Generics,
|
||||
/// The span information for the two where clauses (before equals, after equals)
|
||||
pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
|
||||
/// The index in `generics.where_clause.predicates` that would split into
|
||||
/// predicates from the where clause before the equals and the predicates
|
||||
/// from the where clause after the equals
|
||||
pub where_predicates_split: usize,
|
||||
pub bounds: GenericBounds,
|
||||
pub ty: Option<P<Ty>>,
|
||||
}
|
||||
|
@ -51,7 +51,6 @@ impl AstLike for crate::token::Nonterminal {
|
||||
| Nonterminal::NtMeta(_)
|
||||
| Nonterminal::NtPath(_)
|
||||
| Nonterminal::NtVis(_)
|
||||
| Nonterminal::NtTT(_)
|
||||
| Nonterminal::NtBlock(_)
|
||||
| Nonterminal::NtIdent(..)
|
||||
| Nonterminal::NtLifetime(_) => &[],
|
||||
@ -67,7 +66,6 @@ impl AstLike for crate::token::Nonterminal {
|
||||
| Nonterminal::NtMeta(_)
|
||||
| Nonterminal::NtPath(_)
|
||||
| Nonterminal::NtVis(_)
|
||||
| Nonterminal::NtTT(_)
|
||||
| Nonterminal::NtBlock(_)
|
||||
| Nonterminal::NtIdent(..)
|
||||
| Nonterminal::NtLifetime(_) => {}
|
||||
@ -84,7 +82,7 @@ impl AstLike for crate::token::Nonterminal {
|
||||
Nonterminal::NtPath(path) => path.tokens_mut(),
|
||||
Nonterminal::NtVis(vis) => vis.tokens_mut(),
|
||||
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
||||
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
|
||||
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,13 +75,12 @@ impl NestedMetaItem {
|
||||
pub fn name_value_literal(&self) -> Option<(Symbol, &Lit)> {
|
||||
self.meta_item().and_then(|meta_item| {
|
||||
meta_item.meta_item_list().and_then(|meta_item_list| {
|
||||
if meta_item_list.len() == 1 {
|
||||
if let Some(ident) = meta_item.ident() {
|
||||
if let Some(lit) = meta_item_list[0].literal() {
|
||||
if meta_item_list.len() == 1
|
||||
&& let Some(ident) = meta_item.ident()
|
||||
&& let Some(lit) = meta_item_list[0].literal()
|
||||
{
|
||||
return Some((ident.name, lit));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
})
|
||||
|
@ -12,10 +12,12 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(label_break_value)]
|
||||
#![feature(nll)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![recursion_limit = "256"]
|
||||
#![feature(nll)]
|
||||
#![feature(slice_internals)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
@ -787,7 +787,6 @@ pub fn visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut
|
||||
visit_lazy_tts(tokens, vis);
|
||||
}
|
||||
token::NtPath(path) => vis.visit_path(path),
|
||||
token::NtTT(tt) => visit_tt(tt, vis),
|
||||
token::NtVis(visib) => vis.visit_vis(visib),
|
||||
}
|
||||
}
|
||||
@ -1009,8 +1008,9 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
ItemKind::Mod(unsafety, mod_kind) => {
|
||||
visit_unsafety(unsafety, vis);
|
||||
match mod_kind {
|
||||
ModKind::Loaded(items, _inline, inner_span) => {
|
||||
ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
|
||||
vis.visit_span(inner_span);
|
||||
vis.visit_span(inject_use_span);
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
}
|
||||
ModKind::Unloaded => {}
|
||||
@ -1018,9 +1018,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
}
|
||||
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
|
||||
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
|
||||
ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
ItemKind::TyAlias(box TyAlias {
|
||||
defaultness, generics, where_clauses, bounds, ty, ..
|
||||
}) => {
|
||||
visit_defaultness(defaultness, vis);
|
||||
vis.visit_generics(generics);
|
||||
vis.visit_span(&mut where_clauses.0.1);
|
||||
vis.visit_span(&mut where_clauses.1.1);
|
||||
visit_bounds(bounds, vis);
|
||||
visit_opt(ty, |ty| vis.visit_ty(ty));
|
||||
}
|
||||
@ -1087,9 +1091,18 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
|
||||
visit_fn_sig(sig, visitor);
|
||||
visit_opt(body, |body| visitor.visit_block(body));
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
AssocItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
bounds,
|
||||
ty,
|
||||
..
|
||||
}) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_span(&mut where_clauses.0.1);
|
||||
visitor.visit_span(&mut where_clauses.1.1);
|
||||
visit_bounds(bounds, visitor);
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
}
|
||||
@ -1108,11 +1121,13 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
|
||||
}
|
||||
|
||||
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
|
||||
let Crate { attrs, items, span, id, is_placeholder: _ } = krate;
|
||||
let Crate { attrs, items, spans, id, is_placeholder: _ } = krate;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(attrs, vis);
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
vis.visit_span(span);
|
||||
let ModSpans { inner_span, inject_use_span } = spans;
|
||||
vis.visit_span(inner_span);
|
||||
vis.visit_span(inject_use_span);
|
||||
}
|
||||
|
||||
// Mutates one item into possibly many items.
|
||||
@ -1152,9 +1167,18 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
|
||||
visit_fn_sig(sig, visitor);
|
||||
visit_opt(body, |body| visitor.visit_block(body));
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
bounds,
|
||||
ty,
|
||||
..
|
||||
}) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_span(&mut where_clauses.0.1);
|
||||
visitor.visit_span(&mut where_clauses.1.1);
|
||||
visit_bounds(bounds, visitor);
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
}
|
||||
@ -1536,7 +1560,7 @@ impl DummyAstNode for Crate {
|
||||
Crate {
|
||||
attrs: Default::default(),
|
||||
items: Default::default(),
|
||||
span: Default::default(),
|
||||
spans: Default::default(),
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: Default::default(),
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ pub use TokenKind::*;
|
||||
|
||||
use crate::ast;
|
||||
use crate::ptr::P;
|
||||
use crate::tokenstream::TokenTree;
|
||||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
@ -60,9 +59,9 @@ pub enum LitKind {
|
||||
Integer,
|
||||
Float,
|
||||
Str,
|
||||
StrRaw(u16), // raw string delimited by `n` hash symbols
|
||||
StrRaw(u8), // raw string delimited by `n` hash symbols
|
||||
ByteStr,
|
||||
ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols
|
||||
ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
|
||||
Err,
|
||||
}
|
||||
|
||||
@ -504,11 +503,9 @@ impl Token {
|
||||
|
||||
/// Returns `true` if the token is an interpolated path.
|
||||
fn is_path(&self) -> bool {
|
||||
if let Interpolated(ref nt) = self.kind {
|
||||
if let NtPath(..) = **nt {
|
||||
if let Interpolated(ref nt) = self.kind && let NtPath(..) = **nt {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
@ -516,22 +513,20 @@ impl Token {
|
||||
/// That is, is this a pre-parsed expression dropped into the token stream
|
||||
/// (which happens while parsing the result of macro expansion)?
|
||||
pub fn is_whole_expr(&self) -> bool {
|
||||
if let Interpolated(ref nt) = self.kind {
|
||||
if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
|
||||
if let Interpolated(ref nt) = self.kind
|
||||
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
// Is the token an interpolated block (`$b:block`)?
|
||||
pub fn is_whole_block(&self) -> bool {
|
||||
if let Interpolated(ref nt) = self.kind {
|
||||
if let NtBlock(..) = **nt {
|
||||
if let Interpolated(ref nt) = self.kind && let NtBlock(..) = **nt {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
@ -684,7 +679,6 @@ pub enum Nonterminal {
|
||||
NtMeta(P<ast::AttrItem>),
|
||||
NtPath(ast::Path),
|
||||
NtVis(ast::Visibility),
|
||||
NtTT(TokenTree),
|
||||
}
|
||||
|
||||
// `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
@ -782,7 +776,6 @@ impl Nonterminal {
|
||||
NtMeta(attr_item) => attr_item.span(),
|
||||
NtPath(path) => path.span,
|
||||
NtVis(vis) => vis.span,
|
||||
NtTT(tt) => tt.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -794,7 +787,6 @@ impl PartialEq for Nonterminal {
|
||||
ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
|
||||
}
|
||||
(NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
|
||||
(NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs,
|
||||
// FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
|
||||
// correctly based on data from AST. This will prevent them from matching each other
|
||||
// in macros. The comparison will become possible only when each nonterminal has an
|
||||
@ -817,7 +809,6 @@ impl fmt::Debug for Nonterminal {
|
||||
NtLiteral(..) => f.pad("NtLiteral(..)"),
|
||||
NtMeta(..) => f.pad("NtMeta(..)"),
|
||||
NtPath(..) => f.pad("NtPath(..)"),
|
||||
NtTT(..) => f.pad("NtTT(..)"),
|
||||
NtVis(..) => f.pad("NtVis(..)"),
|
||||
NtLifetime(..) => f.pad("NtLifetime(..)"),
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ impl AttrAnnotatedTokenStream {
|
||||
///
|
||||
/// For example, `#[cfg(FALSE)] struct Foo {}` would
|
||||
/// have an `attrs` field containing the `#[cfg(FALSE)]` attr,
|
||||
/// and a `tokens` field storing the (unparesd) tokens `struct Foo {}`
|
||||
/// and a `tokens` field storing the (unparsed) tokens `struct Foo {}`
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
pub struct AttributesData {
|
||||
/// Attributes, both outer and inner.
|
||||
@ -497,14 +497,15 @@ impl TokenStreamBuilder {
|
||||
|
||||
// If `self` is not empty and the last tree within the last stream is a
|
||||
// token tree marked with `Joint`...
|
||||
if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() {
|
||||
if let Some((TokenTree::Token(last_token), Spacing::Joint)) = last_stream_lrc.last() {
|
||||
if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut()
|
||||
&& let Some((TokenTree::Token(last_token), Spacing::Joint)) = last_stream_lrc.last()
|
||||
// ...and `stream` is not empty and the first tree within it is
|
||||
// a token tree...
|
||||
let TokenStream(ref mut stream_lrc) = stream;
|
||||
if let Some((TokenTree::Token(token), spacing)) = stream_lrc.first() {
|
||||
&& let TokenStream(ref mut stream_lrc) = stream
|
||||
&& let Some((TokenTree::Token(token), spacing)) = stream_lrc.first()
|
||||
// ...and the two tokens can be glued together...
|
||||
if let Some(glued_tok) = last_token.glue(&token) {
|
||||
&& let Some(glued_tok) = last_token.glue(&token)
|
||||
{
|
||||
// ...then do so, by overwriting the last token
|
||||
// tree in `self` and removing the first token tree
|
||||
// from `stream`. This requires using `make_mut()`
|
||||
@ -531,9 +532,6 @@ impl TokenStreamBuilder {
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.0.push(stream);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ pub enum LitError {
|
||||
|
||||
impl LitKind {
|
||||
/// Converts literal token into a semantic literal.
|
||||
fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
|
||||
pub fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
|
||||
let token::Lit { kind, symbol, suffix } = lit;
|
||||
if suffix.is_some() && !kind.may_have_suffix() {
|
||||
return Err(LitError::InvalidSuffix);
|
||||
@ -56,20 +56,25 @@ impl LitKind {
|
||||
// new symbol because the string in the LitKind is different to the
|
||||
// string in the token.
|
||||
let s = symbol.as_str();
|
||||
let symbol =
|
||||
if s.contains(&['\\', '\r']) {
|
||||
let symbol = if s.contains(&['\\', '\r']) {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
|
||||
match unescaped_char {
|
||||
// Force-inlining here is aggressive but the closure is
|
||||
// called on every char in the string, so it can be
|
||||
// hot in programs with many long strings.
|
||||
unescape_literal(
|
||||
&s,
|
||||
Mode::Str,
|
||||
&mut #[inline(always)]
|
||||
|_, unescaped_char| match unescaped_char {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
error = Err(LitError::LexerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
error?;
|
||||
Symbol::intern(&buf)
|
||||
} else {
|
||||
@ -217,11 +222,11 @@ impl Lit {
|
||||
}
|
||||
token::Literal(lit) => lit,
|
||||
token::Interpolated(ref nt) => {
|
||||
if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
|
||||
if let ast::ExprKind::Lit(lit) = &expr.kind {
|
||||
if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt
|
||||
&& let ast::ExprKind::Lit(lit) = &expr.kind
|
||||
{
|
||||
return Ok(lit.clone());
|
||||
}
|
||||
}
|
||||
return Err(LitError::NotLiteral);
|
||||
}
|
||||
_ => return Err(LitError::NotLiteral),
|
||||
|
@ -303,7 +303,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 TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => {
|
||||
ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_ty, ty);
|
||||
@ -559,7 +559,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
|
||||
visitor.visit_fn(kind, span, id);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
|
||||
ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_ty, ty);
|
||||
@ -665,7 +665,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
|
||||
visitor.visit_fn(kind, span, id);
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
|
||||
AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
|
||||
visitor.visit_generics(generics);
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_ty, ty);
|
||||
|
@ -64,12 +64,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let mut clobber_abis = FxHashMap::default();
|
||||
if let Some(asm_arch) = asm_arch {
|
||||
for (abi_name, abi_span) in &asm.clobber_abis {
|
||||
match asm::InlineAsmClobberAbi::parse(
|
||||
asm_arch,
|
||||
&self.sess.target_features,
|
||||
&self.sess.target,
|
||||
*abi_name,
|
||||
) {
|
||||
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) {
|
||||
@ -129,17 +124,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.operands
|
||||
.iter()
|
||||
.map(|(op, op_sp)| {
|
||||
let lower_reg = |reg, is_clobber| match reg {
|
||||
let lower_reg = |reg| match reg {
|
||||
InlineAsmRegOrRegClass::Reg(s) => {
|
||||
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmReg::parse(
|
||||
asm_arch,
|
||||
&sess.target_features,
|
||||
&sess.target,
|
||||
is_clobber,
|
||||
s,
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| {
|
||||
let msg = format!("invalid register `{}`: {}", s.as_str(), e);
|
||||
sess.struct_span_err(*op_sp, &msg).emit();
|
||||
asm::InlineAsmReg::Err
|
||||
@ -163,24 +151,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
let op = match *op {
|
||||
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
|
||||
reg: lower_reg(reg, false),
|
||||
reg: lower_reg(reg),
|
||||
expr: self.lower_expr_mut(expr),
|
||||
},
|
||||
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
|
||||
reg: lower_reg(reg, expr.is_none()),
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
},
|
||||
InlineAsmOperand::InOut { reg, late, ref expr } => {
|
||||
hir::InlineAsmOperand::InOut {
|
||||
reg: lower_reg(reg, false),
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
expr: self.lower_expr_mut(expr),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
|
||||
hir::InlineAsmOperand::SplitInOut {
|
||||
reg: lower_reg(reg, false),
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
in_expr: self.lower_expr_mut(in_expr),
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
@ -339,9 +327,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
let idx2 = *o.get();
|
||||
let &(ref op2, op_sp2) = &operands[idx2];
|
||||
let reg2 = match op2.reg() {
|
||||
Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
|
||||
_ => unreachable!(),
|
||||
let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg() else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let msg = format!(
|
||||
|
@ -330,9 +330,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
args: Vec<AstP<Expr>>,
|
||||
legacy_args_idx: &[usize],
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let path = match f.kind {
|
||||
ExprKind::Path(None, ref mut path) => path,
|
||||
_ => unreachable!(),
|
||||
let ExprKind::Path(None, ref mut path) = f.kind else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
// Split the arguments into const generics and normal arguments
|
||||
@ -619,9 +618,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
/// Desugar `<expr>.await` into:
|
||||
/// ```rust
|
||||
/// match ::std::future::IntoFuture::into_future(<expr>) {
|
||||
/// mut pinned => loop {
|
||||
/// mut __awaitee => loop {
|
||||
/// match unsafe { ::std::future::Future::poll(
|
||||
/// <::std::pin::Pin>::new_unchecked(&mut pinned),
|
||||
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
|
||||
/// ::std::future::get_context(task_context),
|
||||
/// ) } {
|
||||
/// ::std::task::Poll::Ready(result) => break result,
|
||||
@ -658,21 +657,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let expr = self.lower_expr_mut(expr);
|
||||
let expr_hir_id = expr.hir_id;
|
||||
|
||||
let pinned_ident = Ident::with_dummy_span(sym::pinned);
|
||||
let (pinned_pat, pinned_pat_hid) =
|
||||
self.pat_ident_binding_mode(span, pinned_ident, hir::BindingAnnotation::Mutable);
|
||||
// Note that the name of this binding must not be changed to something else because
|
||||
// debuggers and debugger extensions expect it to be called `__awaitee`. They use
|
||||
// this name to identify what is being awaited by a suspended async functions.
|
||||
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
|
||||
let (awaitee_pat, awaitee_pat_hid) =
|
||||
self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable);
|
||||
|
||||
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
|
||||
|
||||
// unsafe {
|
||||
// ::std::future::Future::poll(
|
||||
// ::std::pin::Pin::new_unchecked(&mut pinned),
|
||||
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
|
||||
// ::std::future::get_context(task_context),
|
||||
// )
|
||||
// }
|
||||
let poll_expr = {
|
||||
let pinned = self.expr_ident(span, pinned_ident, pinned_pat_hid);
|
||||
let ref_mut_pinned = self.expr_mut_addr_of(span, pinned);
|
||||
let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);
|
||||
let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);
|
||||
let task_context = if let Some(task_context_hid) = self.task_context {
|
||||
self.expr_ident_mut(span, task_context_ident, task_context_hid)
|
||||
} else {
|
||||
@ -682,7 +684,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let new_unchecked = self.expr_call_lang_item_fn_mut(
|
||||
span,
|
||||
hir::LangItem::PinNewUnchecked,
|
||||
arena_vec![self; ref_mut_pinned],
|
||||
arena_vec![self; ref_mut_awaitee],
|
||||
Some(expr_hir_id),
|
||||
);
|
||||
let get_context = self.expr_call_lang_item_fn_mut(
|
||||
@ -783,8 +785,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: self.lower_span(span),
|
||||
});
|
||||
|
||||
// mut pinned => loop { ... }
|
||||
let pinned_arm = self.arm(pinned_pat, loop_expr);
|
||||
// mut __awaitee => loop { ... }
|
||||
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
|
||||
|
||||
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
|
||||
let into_future_span = self.mark_span_with_reason(
|
||||
@ -800,11 +802,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
|
||||
// match <into_future_expr> {
|
||||
// mut pinned => loop { .. }
|
||||
// mut __awaitee => loop { .. }
|
||||
// }
|
||||
hir::ExprKind::Match(
|
||||
into_future_expr,
|
||||
arena_vec![self; pinned_arm],
|
||||
arena_vec![self; awaitee_arm],
|
||||
hir::MatchSource::AwaitDesugar,
|
||||
)
|
||||
}
|
||||
|
@ -1,16 +1,19 @@
|
||||
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
|
||||
use super::{ImplTraitContext, ImplTraitPosition};
|
||||
use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
|
||||
use crate::{Arena, FnDeclKind};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
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_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_session::utils::NtToTokenstream;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::{respan, DesugaringKind};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
@ -19,128 +22,170 @@ use smallvec::{smallvec, SmallVec};
|
||||
use tracing::debug;
|
||||
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
|
||||
pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
|
||||
pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
|
||||
pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
pub(super) sess: &'a Session,
|
||||
pub(super) resolver: &'a mut dyn ResolverAstLowering,
|
||||
pub(super) nt_to_tokenstream: NtToTokenstream,
|
||||
pub(super) arena: &'hir Arena<'hir>,
|
||||
pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
}
|
||||
|
||||
impl ItemLowerer<'_, '_, '_> {
|
||||
fn with_trait_impl_ref<T>(
|
||||
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
|
||||
/// to the where clause that is preferred, if it exists. Otherwise, it sets the span to the other where
|
||||
/// clause if it exists.
|
||||
fn add_ty_alias_where_clause(
|
||||
generics: &mut ast::Generics,
|
||||
mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
|
||||
prefer_first: bool,
|
||||
) {
|
||||
if !prefer_first {
|
||||
where_clauses = (where_clauses.1, where_clauses.0);
|
||||
}
|
||||
if where_clauses.0.0 || !where_clauses.1.0 {
|
||||
generics.where_clause.has_where_token = where_clauses.0.0;
|
||||
generics.where_clause.span = where_clauses.0.1;
|
||||
} else {
|
||||
generics.where_clause.has_where_token = where_clauses.1.0;
|
||||
generics.where_clause.span = where_clauses.1.1;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
fn with_lctx(
|
||||
&mut self,
|
||||
impl_ref: &Option<TraitRef>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
let old = self.lctx.is_in_trait_impl;
|
||||
self.lctx.is_in_trait_impl = impl_ref.is_some();
|
||||
let ret = f(self);
|
||||
self.lctx.is_in_trait_impl = old;
|
||||
ret
|
||||
}
|
||||
}
|
||||
owner: NodeId,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let mut lctx = LoweringContext {
|
||||
// Pseudo-globals.
|
||||
sess: &self.sess,
|
||||
resolver: self.resolver,
|
||||
nt_to_tokenstream: self.nt_to_tokenstream,
|
||||
arena: self.arena,
|
||||
|
||||
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.
|
||||
}
|
||||
// HirId handling.
|
||||
bodies: Vec::new(),
|
||||
attrs: SortedMap::default(),
|
||||
children: FxHashMap::default(),
|
||||
current_hir_id_owner: CRATE_DEF_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::new(0),
|
||||
node_id_to_local_id: Default::default(),
|
||||
local_id_to_def_id: SortedMap::new(),
|
||||
trait_map: Default::default(),
|
||||
|
||||
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));
|
||||
hir::OwnerNode::Item(node)
|
||||
});
|
||||
// Lowering state.
|
||||
catch_scope: None,
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
is_in_trait_impl: false,
|
||||
is_in_dyn_type: false,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
|
||||
generator_kind: None,
|
||||
task_context: None,
|
||||
current_item: None,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_anonymous_lifetimes: None,
|
||||
in_scope_lifetimes: Vec::new(),
|
||||
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||
allow_into_future: Some([sym::into_future][..].into()),
|
||||
};
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
|
||||
let this = &mut ItemLowerer { lctx: this };
|
||||
match item.kind {
|
||||
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),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
|
||||
match fk {
|
||||
FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => {
|
||||
self.visit_fn_header(&sig.header);
|
||||
visit::walk_fn_decl(self, &sig.decl);
|
||||
// Don't visit the foreign function body even if it has one, since lowering the
|
||||
// body would have no meaning and will have already been caught as a parse error.
|
||||
}
|
||||
_ => visit::walk_fn(self, fk, sp),
|
||||
for (def_id, info) in lctx.children {
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom));
|
||||
self.owners[def_id] = info;
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
|
||||
pub(super) fn lower_node(
|
||||
&mut self,
|
||||
def_id: LocalDefId,
|
||||
) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
if let hir::MaybeOwner::Phantom = self.owners[def_id] {
|
||||
let node = self.ast_index[def_id];
|
||||
match node {
|
||||
AstOwner::NonOwner => {}
|
||||
AstOwner::Crate(c) => self.lower_crate(c),
|
||||
AstOwner::Item(item) => self.lower_item(item),
|
||||
AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt),
|
||||
AstOwner::ForeignItem(item) => self.lower_foreign_item(item),
|
||||
}
|
||||
}
|
||||
|
||||
self.owners[def_id]
|
||||
}
|
||||
|
||||
fn lower_crate(&mut self, c: &Crate) {
|
||||
debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
|
||||
|
||||
self.with_lctx(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, c.spans.inner_span);
|
||||
lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
|
||||
hir::OwnerNode::Crate(lctx.arena.alloc(module))
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_item(&mut self, item: &Item) {
|
||||
self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
|
||||
}
|
||||
|
||||
fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
|
||||
let parent_id = {
|
||||
let parent = self.resolver.definitions().def_key(def_id).parent;
|
||||
let local_def_index = parent.unwrap();
|
||||
LocalDefId { local_def_index }
|
||||
};
|
||||
|
||||
let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item();
|
||||
self.with_lctx(item.id, |lctx| {
|
||||
// Evaluate with the lifetimes in `params` in-scope.
|
||||
// This is used to track which lifetimes have already been defined,
|
||||
// and which need to be replicated when lowering an async fn.
|
||||
match parent_hir.kind {
|
||||
hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => {
|
||||
lctx.is_in_trait_impl = of_trait.is_some();
|
||||
lctx.in_scope_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
|
||||
})
|
||||
.map(|param| param.name)
|
||||
.collect();
|
||||
}
|
||||
hir::ItemKind::Trait(_, _, ref generics, ..) => {
|
||||
lctx.in_scope_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
|
||||
})
|
||||
.map(|param| param.name)
|
||||
.collect();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match ctxt {
|
||||
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
|
||||
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
|
||||
});
|
||||
|
||||
visit::walk_assoc_item(self, item, ctxt);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'a ForeignItem) {
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))
|
||||
});
|
||||
|
||||
visit::walk_foreign_item(self, item);
|
||||
fn lower_foreign_item(&mut self, item: &ForeignItem) {
|
||||
self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// Same as the method above, but accepts `hir::GenericParam`s
|
||||
// instead of `ast::GenericParam`s.
|
||||
// This should only be used with generics that have already had their
|
||||
// in-band lifetimes added. In practice, this means that this function is
|
||||
// only used when lowering a child item of a trait or impl.
|
||||
fn with_parent_item_lifetime_defs<T>(
|
||||
&mut self,
|
||||
parent_hir_id: LocalDefId,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
let old_len = self.in_scope_lifetimes.len();
|
||||
|
||||
let parent_generics = match self.owners[parent_hir_id].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,
|
||||
});
|
||||
self.in_scope_lifetimes.extend(lt_def_names);
|
||||
|
||||
let res = f(self);
|
||||
|
||||
self.in_scope_lifetimes.truncate(old_len);
|
||||
res
|
||||
}
|
||||
|
||||
// Clears (and restores) the `in_scope_lifetimes` field. Used when
|
||||
// visiting nested items, which never inherit in-scope lifetimes
|
||||
// from their surrounding environment.
|
||||
fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
|
||||
|
||||
// this vector is only used when walking over impl headers,
|
||||
// input types, and the like, and should not be non-empty in
|
||||
// between items
|
||||
assert!(self.lifetimes_to_define.is_empty());
|
||||
|
||||
let res = f(self);
|
||||
|
||||
assert!(self.in_scope_lifetimes.is_empty());
|
||||
self.in_scope_lifetimes = old_in_scope_lifetimes;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
|
||||
hir::Mod {
|
||||
inner: self.lower_span(inner),
|
||||
@ -263,7 +308,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
})
|
||||
}
|
||||
ItemKind::Mod(_, ref mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _, inner_span) => {
|
||||
ModKind::Loaded(items, _, ModSpans { inner_span, inject_use_span: _ }) => {
|
||||
hir::ItemKind::Mod(self.lower_mod(items, *inner_span))
|
||||
}
|
||||
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
|
||||
@ -277,7 +322,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ItemKind::GlobalAsm(ref asm) => {
|
||||
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
|
||||
}
|
||||
ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => {
|
||||
ItemKind::TyAlias(box TyAlias {
|
||||
ref generics,
|
||||
where_clauses,
|
||||
ty: Some(ref ty),
|
||||
..
|
||||
}) => {
|
||||
// We lower
|
||||
//
|
||||
// type Foo = impl Trait
|
||||
@ -292,16 +342,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
},
|
||||
);
|
||||
let mut generics = generics.clone();
|
||||
add_ty_alias_where_clause(&mut generics, where_clauses, true);
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
&generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
}
|
||||
ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
|
||||
ItemKind::TyAlias(box TyAlias {
|
||||
ref generics, ref where_clauses, ty: None, ..
|
||||
}) => {
|
||||
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
|
||||
let mut generics = generics.clone();
|
||||
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
&generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
@ -360,7 +416,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// method, it will not be considered an in-band
|
||||
// lifetime to be added, but rather a reference to a
|
||||
// parent lifetime.
|
||||
let lowered_trait_def_id = self.lower_node_id(id).expect_owner();
|
||||
let lowered_trait_def_id = hir_id.expect_owner();
|
||||
let (generics, (trait_ref, lowered_ty)) = self.add_in_band_defs(
|
||||
ast_generics,
|
||||
lowered_trait_def_id,
|
||||
@ -444,8 +500,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
),
|
||||
ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
|
||||
let body = P(self.lower_mac_args(body));
|
||||
|
||||
hir::ItemKind::Macro(ast::MacroDef { body, macro_rules })
|
||||
let macro_kind = self.resolver.decl_macro_kind(self.resolver.local_def_id(id));
|
||||
hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }, macro_kind)
|
||||
}
|
||||
ItemKind::MacCall(..) => {
|
||||
panic!("`TyMac` should have been expanded by now")
|
||||
@ -509,16 +565,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let new_id = self.resolver.local_def_id(new_node_id);
|
||||
let Some(res) = resolutions.next() else {
|
||||
// Associate an HirId to both ids even if there is no resolution.
|
||||
let _old = self
|
||||
.node_id_to_hir_id
|
||||
.insert(new_node_id, hir::HirId::make_owner(new_id));
|
||||
debug_assert!(_old.is_none());
|
||||
self.owners.ensure_contains_elem(new_id, || hir::MaybeOwner::Phantom);
|
||||
let _old = std::mem::replace(
|
||||
&mut self.owners[new_id],
|
||||
let _old = self.children.insert(
|
||||
new_id,
|
||||
hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id)),
|
||||
);
|
||||
debug_assert!(matches!(_old, hir::MaybeOwner::Phantom));
|
||||
debug_assert!(_old.is_none());
|
||||
continue;
|
||||
};
|
||||
let ident = *ident;
|
||||
@ -836,18 +887,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
|
||||
AssocItemKind::TyAlias(box TyAlias {
|
||||
ref generics,
|
||||
where_clauses,
|
||||
ref bounds,
|
||||
ref ty,
|
||||
..
|
||||
}) => {
|
||||
let ty = ty.as_ref().map(|x| {
|
||||
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
});
|
||||
let mut generics = generics.clone();
|
||||
add_ty_alias_where_clause(&mut generics, where_clauses, false);
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
&generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
let kind = hir::TraitItemKind::Type(
|
||||
self.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
ty,
|
||||
);
|
||||
@ -921,9 +980,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
|
||||
AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
|
||||
let mut generics = generics.clone();
|
||||
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
&generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
let kind = match ty {
|
||||
@ -1370,15 +1431,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics: &Generics,
|
||||
itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> GenericsCtor<'hir> {
|
||||
// Error if `?Trait` bounds in where clauses don't refer directly to type paramters.
|
||||
// Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
|
||||
// Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
|
||||
// these into hir when we lower thee where clauses), but this makes it quite difficult to
|
||||
// keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and
|
||||
// where clauses for `?Sized`.
|
||||
for pred in &generics.where_clause.predicates {
|
||||
let bound_pred = match *pred {
|
||||
WherePredicate::BoundPredicate(ref bound_pred) => bound_pred,
|
||||
_ => continue,
|
||||
let WherePredicate::BoundPredicate(ref bound_pred) = *pred else {
|
||||
continue;
|
||||
};
|
||||
let compute_is_param = || {
|
||||
// Check if the where clause type is a plain type parameter.
|
||||
|
@ -35,7 +35,7 @@
|
||||
#![feature(let_else)]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
||||
use rustc_ast::token::{self, Token};
|
||||
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
|
||||
@ -44,7 +44,7 @@ use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
@ -54,19 +54,19 @@ use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{ConstArg, GenericArg, ParamName};
|
||||
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_session::lint::LintBuffer;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
use rustc_span::hygiene::{ExpnId, MacroKind};
|
||||
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::hash_map::Entry;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
macro_rules! arena_vec {
|
||||
@ -99,12 +99,12 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||
/// Used to allocate HIR nodes.
|
||||
arena: &'hir Arena<'hir>,
|
||||
|
||||
/// The items being lowered are collected here.
|
||||
owners: IndexVec<LocalDefId, hir::MaybeOwner<&'hir 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]>,
|
||||
/// Collect items that were created by lowering the current owner.
|
||||
children: FxHashMap<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
|
||||
generator_kind: Option<hir::GeneratorKind>,
|
||||
|
||||
@ -128,36 +128,29 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||
/// written at all (e.g., `&T` or `std::cell::Ref<T>`).
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode,
|
||||
|
||||
/// Used to create lifetime definitions from in-band lifetime usages.
|
||||
/// e.g., `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8`
|
||||
/// When a named lifetime is encountered in a function or impl header and
|
||||
/// has not been defined
|
||||
/// (i.e., it doesn't appear in the in_scope_lifetimes list), it is added
|
||||
/// Used to create lifetime definitions for anonymous lifetimes.
|
||||
/// When an anonymous lifetime is encountered in a function or impl header and
|
||||
/// requires to create a fresh lifetime parameter, it is added
|
||||
/// to this list. The results of this list are then added to the list of
|
||||
/// lifetime definitions in the corresponding impl or function generics.
|
||||
lifetimes_to_define: Vec<(Span, ParamName)>,
|
||||
lifetimes_to_define: Vec<(Span, NodeId)>,
|
||||
|
||||
/// `true` if in-band lifetimes are being collected. This is used to
|
||||
/// indicate whether or not we're in a place where new lifetimes will result
|
||||
/// in in-band lifetime definitions, such a function or an impl header,
|
||||
/// including implicit lifetimes from `impl_header_lifetime_elision`.
|
||||
is_collecting_in_band_lifetimes: bool,
|
||||
/// If anonymous lifetimes are being collected, this field holds the parent
|
||||
/// `LocalDefId` to create the fresh lifetime parameters' `LocalDefId`.
|
||||
is_collecting_anonymous_lifetimes: Option<LocalDefId>,
|
||||
|
||||
/// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
|
||||
/// When `is_collecting_in_band_lifetimes` is true, each lifetime is checked
|
||||
/// against this list to see if it is already in-scope, or if a definition
|
||||
/// needs to be created for it.
|
||||
///
|
||||
/// We always store a `normalize_to_macros_2_0()` version of the param-name in this
|
||||
/// vector.
|
||||
in_scope_lifetimes: Vec<ParamName>,
|
||||
|
||||
current_hir_id_owner: LocalDefId,
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
|
||||
local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
|
||||
trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
|
||||
|
||||
/// NodeIds that are lowered inside the current HIR owner.
|
||||
local_node_ids: Vec<NodeId>,
|
||||
node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>,
|
||||
|
||||
allow_try_trait: Option<Lrc<[Symbol]>>,
|
||||
allow_gen_future: Option<Lrc<[Symbol]>>,
|
||||
@ -165,7 +158,7 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||
}
|
||||
|
||||
pub trait ResolverAstLowering {
|
||||
fn def_key(&mut self, id: DefId) -> DefKey;
|
||||
fn def_key(&self, id: DefId) -> DefKey;
|
||||
|
||||
fn def_span(&self, id: LocalDefId) -> Span;
|
||||
|
||||
@ -177,18 +170,14 @@ pub trait ResolverAstLowering {
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
|
||||
|
||||
/// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
|
||||
fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
|
||||
|
||||
/// Obtains resolution for a label with the given `NodeId`.
|
||||
fn get_label_res(&mut self, id: NodeId) -> Option<NodeId>;
|
||||
|
||||
/// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
|
||||
/// This should only return `None` during testing.
|
||||
fn definitions(&mut self) -> &mut Definitions;
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
|
||||
|
||||
fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
|
||||
|
||||
fn lint_buffer(&mut self) -> &mut LintBuffer;
|
||||
fn definitions(&self) -> &Definitions;
|
||||
|
||||
fn next_node_id(&mut self) -> NodeId;
|
||||
|
||||
@ -208,6 +197,8 @@ pub trait ResolverAstLowering {
|
||||
expn_id: ExpnId,
|
||||
span: Span,
|
||||
) -> LocalDefId;
|
||||
|
||||
fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
|
||||
}
|
||||
|
||||
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
|
||||
@ -341,6 +332,81 @@ impl FnDeclKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum AstOwner<'a> {
|
||||
NonOwner,
|
||||
Crate(&'a ast::Crate),
|
||||
Item(&'a ast::Item),
|
||||
AssocItem(&'a ast::AssocItem, visit::AssocCtxt),
|
||||
ForeignItem(&'a ast::ForeignItem),
|
||||
}
|
||||
|
||||
fn index_crate<'a>(
|
||||
resolver: &dyn ResolverAstLowering,
|
||||
krate: &'a Crate,
|
||||
) -> IndexVec<LocalDefId, AstOwner<'a>> {
|
||||
let mut indexer = Indexer { resolver, index: IndexVec::new() };
|
||||
indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner);
|
||||
indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate);
|
||||
visit::walk_crate(&mut indexer, krate);
|
||||
return indexer.index;
|
||||
|
||||
struct Indexer<'s, 'a> {
|
||||
resolver: &'s dyn ResolverAstLowering,
|
||||
index: IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> visit::Visitor<'a> for Indexer<'_, '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 ast::Item) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
|
||||
self.index[def_id] = AstOwner::Item(item);
|
||||
visit::walk_item(self, item)
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
|
||||
self.index[def_id] = AstOwner::AssocItem(item, ctxt);
|
||||
visit::walk_assoc_item(self, item, ctxt);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
|
||||
self.index[def_id] = AstOwner::ForeignItem(item);
|
||||
visit::walk_foreign_item(self, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(
|
||||
resolver: &mut dyn ResolverAstLowering,
|
||||
owners: &IndexVec<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
|
||||
) -> Fingerprint {
|
||||
let mut hir_body_nodes: Vec<_> = owners
|
||||
.iter_enumerated()
|
||||
.filter_map(|(def_id, info)| {
|
||||
let info = info.as_owner()?;
|
||||
let def_path_hash = resolver.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 = resolver.create_stable_hashing_context();
|
||||
hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
stable_hasher.finish()
|
||||
}
|
||||
|
||||
pub fn lower_crate<'a, 'hir>(
|
||||
sess: &'a Session,
|
||||
krate: &'a Crate,
|
||||
@ -350,37 +416,26 @@ pub fn lower_crate<'a, 'hir>(
|
||||
) -> &'hir hir::Crate<'hir> {
|
||||
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
|
||||
|
||||
let owners =
|
||||
let ast_index = index_crate(resolver, krate);
|
||||
|
||||
let mut owners =
|
||||
IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count());
|
||||
LoweringContext {
|
||||
|
||||
for def_id in ast_index.indices() {
|
||||
item::ItemLowerer {
|
||||
sess,
|
||||
resolver,
|
||||
nt_to_tokenstream,
|
||||
arena,
|
||||
owners,
|
||||
bodies: Vec::new(),
|
||||
attrs: SortedMap::new(),
|
||||
catch_scope: None,
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
is_in_trait_impl: false,
|
||||
is_in_dyn_type: false,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
|
||||
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,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_in_band_lifetimes: false,
|
||||
in_scope_lifetimes: Vec::new(),
|
||||
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||
allow_into_future: Some([sym::into_future][..].into()),
|
||||
ast_index: &ast_index,
|
||||
owners: &mut owners,
|
||||
}
|
||||
.lower_crate(krate)
|
||||
.lower_node(def_id);
|
||||
}
|
||||
|
||||
let hir_hash = compute_hir_hash(resolver, &owners);
|
||||
let krate = hir::Crate { owners, hir_hash };
|
||||
arena.alloc(krate)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
@ -449,62 +504,25 @@ enum AnonymousLifetimeMode {
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
|
||||
debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
|
||||
|
||||
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
|
||||
|
||||
self.with_hir_id_owner(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, c.span);
|
||||
lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
|
||||
hir::OwnerNode::Crate(lctx.arena.alloc(module))
|
||||
});
|
||||
|
||||
let hir_hash = self.compute_hir_hash();
|
||||
|
||||
let krate = hir::Crate { owners: self.owners, hir_hash };
|
||||
self.arena.alloc(krate)
|
||||
}
|
||||
|
||||
/// 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_owner()?;
|
||||
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(
|
||||
&mut self,
|
||||
owner: NodeId,
|
||||
f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
|
||||
) -> LocalDefId {
|
||||
) {
|
||||
let def_id = self.resolver.local_def_id(owner);
|
||||
|
||||
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_node_ids = std::mem::take(&mut self.node_id_to_local_id);
|
||||
let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
|
||||
let current_trait_map = std::mem::take(&mut self.trait_map);
|
||||
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));
|
||||
|
||||
// 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));
|
||||
let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
|
||||
debug_assert_eq!(_old, None);
|
||||
self.local_node_ids.push(owner);
|
||||
|
||||
let item = f(self);
|
||||
debug_assert_eq!(def_id, item.def_id());
|
||||
@ -512,47 +530,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
self.attrs = current_attrs;
|
||||
self.bodies = current_bodies;
|
||||
self.local_node_ids = current_node_ids;
|
||||
self.node_id_to_local_id = current_node_ids;
|
||||
self.local_id_to_def_id = current_id_to_def_id;
|
||||
self.trait_map = current_trait_map;
|
||||
self.current_hir_id_owner = current_owner;
|
||||
self.item_local_id_counter = current_local_counter;
|
||||
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
self.owners[def_id] = hir::MaybeOwner::Owner(self.arena.alloc(info));
|
||||
|
||||
def_id
|
||||
let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info));
|
||||
debug_assert!(_old.is_none())
|
||||
}
|
||||
|
||||
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
|
||||
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'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 local_id_to_def_id = local_node_ids
|
||||
.iter()
|
||||
.filter_map(|&node_id| {
|
||||
let hir_id = self.node_id_to_hir_id[node_id]?;
|
||||
if hir_id.local_id == hir::ItemLocalId::new(0) {
|
||||
None
|
||||
} else {
|
||||
let def_id = self.resolver.opt_local_def_id(node_id)?;
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
if let o @ hir::MaybeOwner::Phantom = &mut self.owners[def_id] {
|
||||
// Do not override a `MaybeOwner::Owner` that may already here.
|
||||
*o = hir::MaybeOwner::NonOwner(hir_id);
|
||||
}
|
||||
Some((hir_id.local_id, def_id))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
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();
|
||||
let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
|
||||
let trait_map = std::mem::take(&mut self.trait_map);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (id, attrs) in attrs.iter() {
|
||||
@ -582,7 +574,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir::AttributeMap { map: attrs, hash }
|
||||
};
|
||||
|
||||
hir::OwnerInfo { nodes, parenting, attrs, trait_map }
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
|
||||
}
|
||||
|
||||
/// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
|
||||
@ -615,14 +607,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
|
||||
assert_ne!(ast_node_id, DUMMY_NODE_ID);
|
||||
|
||||
*self.node_id_to_hir_id.get_or_insert_with(ast_node_id, || {
|
||||
match self.node_id_to_local_id.entry(ast_node_id) {
|
||||
Entry::Occupied(o) => {
|
||||
hir::HirId { owner: self.current_hir_id_owner, local_id: *o.get() }
|
||||
}
|
||||
Entry::Vacant(v) => {
|
||||
// Generate a new `HirId`.
|
||||
let owner = self.current_hir_id_owner;
|
||||
let local_id = self.item_local_id_counter;
|
||||
let hir_id = hir::HirId { owner, local_id };
|
||||
|
||||
v.insert(local_id);
|
||||
self.item_local_id_counter.increment_by(1);
|
||||
self.local_node_ids.push(ast_node_id);
|
||||
hir::HirId { owner, local_id }
|
||||
})
|
||||
|
||||
assert_ne!(local_id, hir::ItemLocalId::new(0));
|
||||
if let Some(def_id) = self.resolver.opt_local_def_id(ast_node_id) {
|
||||
// Do not override a `MaybeOwner::Owner` that may already here.
|
||||
self.children.entry(def_id).or_insert(hir::MaybeOwner::NonOwner(hir_id));
|
||||
self.local_id_to_def_id.insert(local_id, def_id);
|
||||
}
|
||||
|
||||
if let Some(traits) = self.resolver.take_trait_map(ast_node_id) {
|
||||
self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice());
|
||||
}
|
||||
|
||||
hir_id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next_id(&mut self) -> hir::HirId {
|
||||
@ -631,11 +642,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn lower_res(&mut self, res: Res<NodeId>) -> Res {
|
||||
res.map_id(|id| {
|
||||
self.node_id_to_hir_id.get(id).copied().flatten().unwrap_or_else(|| {
|
||||
panic!("expected `NodeId` to be lowered already for res {:#?}", res);
|
||||
})
|
||||
})
|
||||
let res: Result<Res, ()> = res.apply_id(|id| {
|
||||
let owner = self.current_hir_id_owner;
|
||||
let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?;
|
||||
Ok(hir::HirId { owner, local_id })
|
||||
});
|
||||
// We may fail to find a HirId when the Res points to a Local from an enclosing HIR owner.
|
||||
// This can happen when trying to lower the return type `x` in erroneous code like
|
||||
// async fn foo(x: u8) -> x {}
|
||||
// In that case, `x` is lowered as a function parameter, and the return type is lowered as
|
||||
// an opaque type as a synthesized HIR owner.
|
||||
res.unwrap_or(Res::Err)
|
||||
}
|
||||
|
||||
fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> {
|
||||
@ -716,90 +733,56 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
/// parameter while `f` is running (and restored afterwards).
|
||||
fn collect_in_band_defs<T>(
|
||||
&mut self,
|
||||
parent_def_id: LocalDefId,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> (Vec<(Span, ParamName)>, T) {
|
||||
let was_collecting = std::mem::replace(&mut self.is_collecting_in_band_lifetimes, true);
|
||||
) -> (Vec<(Span, NodeId)>, T) {
|
||||
let was_collecting =
|
||||
std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, Some(parent_def_id));
|
||||
let len = self.lifetimes_to_define.len();
|
||||
|
||||
let res = f(self);
|
||||
|
||||
let lifetimes_to_define = self.lifetimes_to_define.split_off(len);
|
||||
self.is_collecting_in_band_lifetimes = was_collecting;
|
||||
self.is_collecting_anonymous_lifetimes = was_collecting;
|
||||
(lifetimes_to_define, res)
|
||||
}
|
||||
|
||||
/// Converts a lifetime into a new generic parameter.
|
||||
fn lifetime_to_generic_param(
|
||||
fn fresh_lifetime_to_generic_param(
|
||||
&mut self,
|
||||
span: Span,
|
||||
hir_name: ParamName,
|
||||
parent_def_id: LocalDefId,
|
||||
node_id: NodeId,
|
||||
) -> hir::GenericParam<'hir> {
|
||||
let node_id = self.resolver.next_node_id();
|
||||
|
||||
// Get the name we'll use to make the def-path. Note
|
||||
// that collisions are ok here and this shouldn't
|
||||
// really show up for end-user.
|
||||
let (str_name, kind) = match hir_name {
|
||||
ParamName::Plain(ident) => (ident.name, hir::LifetimeParamKind::InBand),
|
||||
ParamName::Fresh(_) => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Elided),
|
||||
ParamName::Error => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Error),
|
||||
};
|
||||
|
||||
// Add a definition for the in-band lifetime def.
|
||||
self.resolver.create_def(
|
||||
parent_def_id,
|
||||
node_id,
|
||||
DefPathData::LifetimeNs(str_name),
|
||||
ExpnId::root(),
|
||||
span.with_parent(None),
|
||||
);
|
||||
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
let def_id = self.resolver.local_def_id(node_id);
|
||||
hir::GenericParam {
|
||||
hir_id: self.lower_node_id(node_id),
|
||||
name: hir_name,
|
||||
hir_id,
|
||||
name: hir::ParamName::Fresh(def_id),
|
||||
bounds: &[],
|
||||
span: self.lower_span(span),
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
kind: hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided },
|
||||
}
|
||||
}
|
||||
|
||||
/// When there is a reference to some lifetime `'a`, and in-band
|
||||
/// lifetimes are enabled, then we want to push that lifetime into
|
||||
/// the vector of names to define later. In that case, it will get
|
||||
/// added to the appropriate generics.
|
||||
fn maybe_collect_in_band_lifetime(&mut self, ident: Ident) {
|
||||
if !self.is_collecting_in_band_lifetimes {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.sess.features_untracked().in_band_lifetimes {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.normalize_to_macros_2_0())) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hir_name = ParamName::Plain(ident);
|
||||
|
||||
if self.lifetimes_to_define.iter().any(|(_, lt_name)| {
|
||||
lt_name.normalize_to_macros_2_0() == hir_name.normalize_to_macros_2_0()
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.lifetimes_to_define.push((ident.span, hir_name));
|
||||
}
|
||||
|
||||
/// When we have either an elided or `'_` lifetime in an impl
|
||||
/// header, we convert it to an in-band lifetime.
|
||||
fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName {
|
||||
assert!(self.is_collecting_in_band_lifetimes);
|
||||
let index = self.lifetimes_to_define.len() + self.in_scope_lifetimes.len();
|
||||
let hir_name = ParamName::Fresh(index);
|
||||
self.lifetimes_to_define.push((span, hir_name));
|
||||
fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName {
|
||||
let Some(parent_def_id) = self.is_collecting_anonymous_lifetimes else { panic!() };
|
||||
|
||||
let node_id = self.resolver.next_node_id();
|
||||
|
||||
// Add a definition for the in-band lifetime def.
|
||||
let param_def_id = self.resolver.create_def(
|
||||
parent_def_id,
|
||||
node_id,
|
||||
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
|
||||
ExpnId::root(),
|
||||
span.with_parent(None),
|
||||
);
|
||||
|
||||
let hir_name = ParamName::Fresh(param_def_id);
|
||||
self.lifetimes_to_define.push((span, node_id));
|
||||
hir_name
|
||||
}
|
||||
|
||||
@ -841,7 +824,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
|
||||
) -> (hir::Generics<'hir>, T) {
|
||||
let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self
|
||||
.collect_in_band_defs(|this| {
|
||||
.collect_in_band_defs(parent_def_id, |this| {
|
||||
this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| {
|
||||
this.with_in_scope_lifetime_defs(&generics.params, |this| {
|
||||
let mut impl_trait_defs = Vec::new();
|
||||
@ -868,9 +851,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
lowered_generics.params.extend(
|
||||
lifetimes_to_define
|
||||
.into_iter()
|
||||
.map(|(span, hir_name)| {
|
||||
self.lifetime_to_generic_param(span, hir_name, parent_def_id)
|
||||
})
|
||||
.map(|(span, node_id)| self.fresh_lifetime_to_generic_param(span, node_id))
|
||||
.chain(impl_trait_defs),
|
||||
);
|
||||
|
||||
@ -988,7 +969,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
sess.diagnostic().delay_span_bug(
|
||||
span,
|
||||
"unexpected delimiter in key-value attribute's value",
|
||||
)
|
||||
);
|
||||
}
|
||||
unwrap_single_token(sess, tokens, span)
|
||||
}
|
||||
@ -1476,7 +1457,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let lifetime_defs =
|
||||
lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(|&(name, span)| {
|
||||
let def_node_id = lctx.resolver.next_node_id();
|
||||
let hir_id = lctx.lower_node_id(def_node_id);
|
||||
lctx.resolver.create_def(
|
||||
opaque_ty_def_id,
|
||||
def_node_id,
|
||||
@ -1484,6 +1464,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ExpnId::root(),
|
||||
span.with_parent(None),
|
||||
);
|
||||
let hir_id = lctx.lower_node_id(def_node_id);
|
||||
|
||||
let (name, kind) = match name {
|
||||
hir::LifetimeName::Underscore => (
|
||||
@ -1787,15 +1768,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.in_scope_lifetimes
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|name| (name.ident().span, name, hir::LifetimeName::Param(name)))
|
||||
.chain(
|
||||
self.lifetimes_to_define
|
||||
.iter()
|
||||
.map(|&(span, name)| (span, name, hir::LifetimeName::Param(name))),
|
||||
)
|
||||
.map(|name| (name.ident().span, hir::LifetimeName::Param(name)))
|
||||
.chain(self.lifetimes_to_define.iter().map(|&(span, node_id)| {
|
||||
let def_id = self.resolver.local_def_id(node_id);
|
||||
let name = hir::ParamName::Fresh(def_id);
|
||||
(span, hir::LifetimeName::Param(name))
|
||||
}))
|
||||
.collect();
|
||||
|
||||
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
||||
let mut generic_params: Vec<_> = lifetime_params
|
||||
.iter()
|
||||
.map(|&(span, name)| {
|
||||
// We can only get lifetime names from the outside.
|
||||
let hir::LifetimeName::Param(hir_name) = name else { panic!() };
|
||||
|
||||
let node_id = this.resolver.next_node_id();
|
||||
|
||||
// Add a definition for the in-band lifetime def.
|
||||
let def_id = this.resolver.create_def(
|
||||
opaque_ty_def_id,
|
||||
node_id,
|
||||
DefPathData::LifetimeNs(hir_name.ident().name),
|
||||
ExpnId::root(),
|
||||
span.with_parent(None),
|
||||
);
|
||||
|
||||
let (kind, name) = match hir_name {
|
||||
ParamName::Plain(ident) => {
|
||||
(hir::LifetimeParamKind::Explicit, hir::ParamName::Plain(ident))
|
||||
}
|
||||
ParamName::Fresh(_) => {
|
||||
(hir::LifetimeParamKind::Elided, hir::ParamName::Fresh(def_id))
|
||||
}
|
||||
ParamName::Error => (hir::LifetimeParamKind::Error, hir::ParamName::Error),
|
||||
};
|
||||
|
||||
hir::GenericParam {
|
||||
hir_id: this.lower_node_id(node_id),
|
||||
name,
|
||||
bounds: &[],
|
||||
span: this.lower_span(span),
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// We have to be careful to get elision right here. The
|
||||
// idea is that we create a lifetime parameter for each
|
||||
// lifetime in the return type. So, given a return type
|
||||
@ -1806,25 +1825,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// hence the elision takes place at the fn site.
|
||||
let (lifetimes_to_define, future_bound) =
|
||||
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
|
||||
this.collect_in_band_defs(|this| {
|
||||
this.collect_in_band_defs(opaque_ty_def_id, |this| {
|
||||
this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
|
||||
})
|
||||
});
|
||||
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
|
||||
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
|
||||
|
||||
lifetime_params.extend(
|
||||
// Output lifetime like `'_`:
|
||||
lifetimes_to_define
|
||||
.into_iter()
|
||||
.map(|(span, name)| (span, name, hir::LifetimeName::Implicit(false))),
|
||||
);
|
||||
for (span, node_id) in lifetimes_to_define {
|
||||
let param = this.fresh_lifetime_to_generic_param(span, node_id);
|
||||
lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
|
||||
generic_params.push(param);
|
||||
}
|
||||
let generic_params = this.arena.alloc_from_iter(generic_params);
|
||||
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
|
||||
|
||||
let generic_params =
|
||||
this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name, _)| {
|
||||
this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id)
|
||||
}));
|
||||
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
|
||||
|
||||
let opaque_ty_item = hir::OpaqueTy {
|
||||
generics: hir::Generics {
|
||||
@ -1857,7 +1873,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// For the "output" lifetime parameters, we just want to
|
||||
// generate `'_`.
|
||||
let generic_args =
|
||||
self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _, name)| {
|
||||
self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, name)| {
|
||||
GenericArg::Lifetime(hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(span),
|
||||
@ -1938,7 +1954,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
ident if ident.name == kw::UnderscoreLifetime => match self.anonymous_lifetime_mode {
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
let fresh_name = self.collect_fresh_in_band_lifetime(span);
|
||||
let fresh_name = self.collect_fresh_anonymous_lifetime(span);
|
||||
self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name))
|
||||
}
|
||||
|
||||
@ -1949,7 +1965,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
|
||||
},
|
||||
ident => {
|
||||
self.maybe_collect_in_band_lifetime(ident);
|
||||
let param_name = ParamName::Plain(self.lower_ident(ident));
|
||||
self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name))
|
||||
}
|
||||
@ -1993,8 +2008,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
let (name, kind) = match param.kind {
|
||||
GenericParamKind::Lifetime => {
|
||||
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
|
||||
self.is_collecting_in_band_lifetimes = false;
|
||||
let was_collecting_in_band = self.is_collecting_anonymous_lifetimes;
|
||||
self.is_collecting_anonymous_lifetimes = None;
|
||||
|
||||
let lt = self
|
||||
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
||||
@ -2017,7 +2032,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let kind =
|
||||
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
|
||||
|
||||
self.is_collecting_in_band_lifetimes = was_collecting_in_band;
|
||||
self.is_collecting_anonymous_lifetimes = was_collecting_in_band;
|
||||
|
||||
(param_name, kind)
|
||||
}
|
||||
@ -2089,17 +2104,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
)),
|
||||
_ => None,
|
||||
});
|
||||
if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
|
||||
itctx
|
||||
{
|
||||
if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
|
||||
capturable_lifetimes.extend(lt_def_names.clone());
|
||||
}
|
||||
|
||||
let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
|
||||
|
||||
if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
|
||||
itctx
|
||||
{
|
||||
if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
|
||||
for param in lt_def_names {
|
||||
capturable_lifetimes.remove(¶m);
|
||||
}
|
||||
@ -2376,7 +2387,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
|
||||
// `'f`.
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
let fresh_name = self.collect_fresh_in_band_lifetime(span);
|
||||
let fresh_name = self.collect_fresh_anonymous_lifetime(span);
|
||||
hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(span),
|
||||
|
@ -4,7 +4,7 @@ version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.10"
|
||||
itertools = "0.10.1"
|
||||
tracing = "0.1"
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
@ -11,11 +11,13 @@ use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY};
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
};
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
@ -62,8 +64,8 @@ struct AstValidator<'a> {
|
||||
/// certain positions.
|
||||
is_assoc_ty_bound_banned: bool,
|
||||
|
||||
/// Used to allow `let` expressions in certain syntactic locations.
|
||||
is_let_allowed: bool,
|
||||
/// See [ForbiddenLetReason]
|
||||
forbidden_let_reason: Option<ForbiddenLetReason>,
|
||||
|
||||
lint_buffer: &'a mut LintBuffer,
|
||||
}
|
||||
@ -101,20 +103,31 @@ impl<'a> AstValidator<'a> {
|
||||
self.is_tilde_const_allowed = old;
|
||||
}
|
||||
|
||||
fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
|
||||
let old = mem::replace(&mut self.is_let_allowed, allowed);
|
||||
fn with_let_management(
|
||||
&mut self,
|
||||
forbidden_let_reason: Option<ForbiddenLetReason>,
|
||||
f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
|
||||
) {
|
||||
let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
|
||||
f(self, old);
|
||||
self.is_let_allowed = old;
|
||||
self.forbidden_let_reason = old;
|
||||
}
|
||||
|
||||
/// Emits an error banning the `let` expression provided in the given location.
|
||||
fn ban_let_expr(&self, expr: &'a Expr) {
|
||||
fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
|
||||
let sess = &self.session;
|
||||
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 parentheses in those conditions")
|
||||
.emit();
|
||||
let err = "`let` expressions are not supported here";
|
||||
let mut diag = sess.struct_span_err(expr.span, err);
|
||||
diag.note("only supported directly in conditions of `if` and `while` expressions");
|
||||
diag.note("as well as when nested within `&&` and parentheses in those conditions");
|
||||
if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
|
||||
diag.span_note(
|
||||
span,
|
||||
"`||` operators are not currently supported in let chain expressions",
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
} else {
|
||||
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
|
||||
.note("variable declaration using `let` is a statement")
|
||||
@ -122,6 +135,42 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_gat_where(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
before_predicates: &[WherePredicate],
|
||||
where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
|
||||
) {
|
||||
if !before_predicates.is_empty() {
|
||||
let mut state = State::new();
|
||||
if !where_clauses.1.0 {
|
||||
state.space();
|
||||
state.word_space("where");
|
||||
} else {
|
||||
state.word_space(",");
|
||||
}
|
||||
let mut first = true;
|
||||
for p in before_predicates.iter() {
|
||||
if !first {
|
||||
state.word_space(",");
|
||||
}
|
||||
first = false;
|
||||
state.print_where_predicate(p);
|
||||
}
|
||||
let suggestion = state.s.eof();
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
id,
|
||||
where_clauses.0.1,
|
||||
"where clause not allowed here",
|
||||
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
||||
where_clauses.1.1.shrink_to_hi(),
|
||||
suggestion,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
|
||||
f(self);
|
||||
@ -394,7 +443,7 @@ impl<'a> AstValidator<'a> {
|
||||
attr.span,
|
||||
"allow, cfg, cfg_attr, deny, \
|
||||
forbid, and warn are the only allowed built-in attributes in function parameters",
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -425,10 +474,17 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
|
||||
fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
|
||||
let source_map = self.session.source_map();
|
||||
let end = source_map.end_point(sp);
|
||||
let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
|
||||
end
|
||||
} else {
|
||||
sp.shrink_to_hi()
|
||||
};
|
||||
self.err_handler()
|
||||
.struct_span_err(sp, msg)
|
||||
.span_suggestion(
|
||||
self.session.source_map().end_point(sp),
|
||||
replace_span,
|
||||
&format!("provide a definition for the {}", ctx),
|
||||
sugg.to_string(),
|
||||
Applicability::HasPlaceholders,
|
||||
@ -454,7 +510,7 @@ impl<'a> AstValidator<'a> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn check_foreign_ty_genericless(&self, generics: &Generics) {
|
||||
fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
|
||||
let cannot_have = |span, descr, remove_descr| {
|
||||
self.err_handler()
|
||||
.struct_span_err(
|
||||
@ -477,14 +533,13 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
|
||||
if !generics.where_clause.predicates.is_empty() {
|
||||
cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
|
||||
cannot_have(where_span, "`where` clauses", "`where` clause");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
|
||||
let body = match body {
|
||||
None => return,
|
||||
Some(body) => body,
|
||||
let Some(body) = body else {
|
||||
return;
|
||||
};
|
||||
self.err_handler()
|
||||
.struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
|
||||
@ -504,9 +559,8 @@ impl<'a> AstValidator<'a> {
|
||||
|
||||
/// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
|
||||
fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
|
||||
let body = match body {
|
||||
None => return,
|
||||
Some(body) => body,
|
||||
let Some(body) = body else {
|
||||
return;
|
||||
};
|
||||
self.err_handler()
|
||||
.struct_span_err(ident.span, "incorrect function inside `extern` block")
|
||||
@ -568,9 +622,9 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reject C-varadic type unless the function is foreign,
|
||||
/// Reject C-variadic type unless the function is foreign,
|
||||
/// or free and `unsafe extern "C"` semantically.
|
||||
fn check_c_varadic_type(&self, fk: FnKind<'a>) {
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
|
||||
match (fk.ctxt(), fk.header()) {
|
||||
(Some(FnCtxt::Foreign), _) => return,
|
||||
(Some(FnCtxt::Free), Some(header)) => match header.ext {
|
||||
@ -952,39 +1006,48 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
|
||||
self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
|
||||
match &expr.kind {
|
||||
ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
|
||||
let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
|
||||
this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
|
||||
this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
|
||||
}
|
||||
ExprKind::If(cond, then, opt_else) => {
|
||||
this.visit_block(then);
|
||||
walk_list!(this, visit_expr, opt_else);
|
||||
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
|
||||
this.with_let_management(None, |this, _| this.visit_expr(cond));
|
||||
return;
|
||||
}
|
||||
ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
|
||||
ExprKind::Match(expr, arms) => {
|
||||
this.visit_expr(expr);
|
||||
ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
|
||||
this.ban_let_expr(expr, elem);
|
||||
},
|
||||
ExprKind::Match(scrutinee, arms) => {
|
||||
this.visit_expr(scrutinee);
|
||||
for arm in arms {
|
||||
this.visit_expr(&arm.body);
|
||||
this.visit_pat(&arm.pat);
|
||||
walk_list!(this, visit_attribute, &arm.attrs);
|
||||
if let Some(ref guard) = arm.guard {
|
||||
if let ExprKind::Let(_, ref expr, _) = guard.kind {
|
||||
this.with_let_allowed(true, |this, _| this.visit_expr(expr));
|
||||
if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
|
||||
this.with_let_management(None, |this, _| {
|
||||
this.visit_expr(guard_expr)
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
|
||||
this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
|
||||
this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
|
||||
return;
|
||||
}
|
||||
ExprKind::While(cond, then, opt_label) => {
|
||||
walk_list!(this, visit_label, opt_label);
|
||||
this.visit_block(then);
|
||||
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
|
||||
this.with_let_management(None, |this, _| this.visit_expr(cond));
|
||||
return;
|
||||
}
|
||||
_ => visit::walk_expr(this, expr),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1225,13 +1288,29 @@ 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 TyAlias { defaultness, ref bounds, ref ty, .. }) => {
|
||||
ItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
where_clauses,
|
||||
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>;");
|
||||
}
|
||||
self.check_type_no_bounds(bounds, "this context");
|
||||
if where_clauses.1.0 {
|
||||
let mut err = self.err_handler().struct_span_err(
|
||||
where_clauses.1.1,
|
||||
"where clauses are not allowed after the type for type aliases",
|
||||
);
|
||||
err.note(
|
||||
"see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -1247,11 +1326,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
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_ty_genericless(generics, where_clauses.0.1);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
ForeignItemKind::Static(_, _, body) => {
|
||||
@ -1418,7 +1504,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
};
|
||||
self.check_fn_decl(fk.decl(), self_semantic);
|
||||
|
||||
self.check_c_varadic_type(fk);
|
||||
self.check_c_variadic_type(fk);
|
||||
|
||||
// Functions cannot both be `const async`
|
||||
if let Some(FnHeader {
|
||||
@ -1505,9 +1591,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
|
||||
AssocItemKind::TyAlias(box TyAlias {
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
bounds,
|
||||
ty,
|
||||
..
|
||||
}) => {
|
||||
self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
|
||||
self.check_type_no_bounds(bounds, "`impl`s");
|
||||
if ty.is_some() {
|
||||
self.check_gat_where(
|
||||
item.id,
|
||||
generics.where_clause.predicates.split_at(*where_predicates_split).0,
|
||||
*where_clauses,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -1699,10 +1799,19 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
|
||||
is_tilde_const_allowed: false,
|
||||
is_impl_trait_banned: false,
|
||||
is_assoc_ty_bound_banned: false,
|
||||
is_let_allowed: false,
|
||||
forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
|
||||
lint_buffer: lints,
|
||||
};
|
||||
visit::walk_crate(&mut validator, krate);
|
||||
|
||||
validator.has_proc_macro_decls
|
||||
}
|
||||
|
||||
/// Used to forbid `let` expressions in certain syntactic locations.
|
||||
#[derive(Clone, Copy)]
|
||||
enum ForbiddenLetReason {
|
||||
/// A let chain with the `||` operator
|
||||
ForbiddenWithOr(Span),
|
||||
/// `let` is not valid and the source environment is not important
|
||||
GenericForbidden,
|
||||
}
|
||||
|
@ -252,11 +252,12 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
"wasm ABI is experimental and subject to change"
|
||||
);
|
||||
}
|
||||
abi => self
|
||||
.sess
|
||||
.parse_sess
|
||||
.span_diagnostic
|
||||
.delay_span_bug(span, &format!("unrecognized ABI not caught in lowering: {}", abi)),
|
||||
abi => {
|
||||
self.sess.parse_sess.span_diagnostic.delay_span_bug(
|
||||
span,
|
||||
&format!("unrecognized ABI not caught in lowering: {}", abi),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,13 +387,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
if attr.has_name(sym::link) {
|
||||
for nested_meta in attr.meta_item_list().unwrap_or_default() {
|
||||
if nested_meta.has_name(sym::modifiers) {
|
||||
gate_feature_post!(
|
||||
self,
|
||||
native_link_modifiers,
|
||||
nested_meta.span(),
|
||||
"native link modifiers are experimental"
|
||||
);
|
||||
|
||||
if let Some(modifiers) = nested_meta.value_str() {
|
||||
for modifier in modifiers.as_str().split(',') {
|
||||
if let Some(modifier) = modifier.strip_prefix(&['+', '-']) {
|
||||
@ -411,7 +405,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
gate_modifier!(
|
||||
"bundle" => native_link_modifiers_bundle
|
||||
"verbatim" => native_link_modifiers_verbatim
|
||||
"whole-archive" => native_link_modifiers_whole_archive
|
||||
"as-needed" => native_link_modifiers_as_needed
|
||||
);
|
||||
}
|
||||
@ -420,6 +413,24 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit errors for non-staged-api crates.
|
||||
if !self.features.staged_api {
|
||||
if attr.has_name(sym::rustc_deprecated)
|
||||
|| attr.has_name(sym::unstable)
|
||||
|| attr.has_name(sym::stable)
|
||||
|| attr.has_name(sym::rustc_const_unstable)
|
||||
|| attr.has_name(sym::rustc_const_stable)
|
||||
{
|
||||
struct_span_err!(
|
||||
self.sess,
|
||||
attr.span,
|
||||
E0734,
|
||||
"stability attributes may not be used outside of the standard library",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'a ast::Item) {
|
||||
|
@ -4,11 +4,13 @@
|
||||
//!
|
||||
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
|
||||
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![recursion_limit = "256"]
|
||||
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
|
||||
|
||||
pub mod ast_validation;
|
||||
pub mod feature_gate;
|
||||
|
@ -57,9 +57,8 @@ impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
|
||||
}
|
||||
|
||||
pub fn run(span_diagnostic: &rustc_errors::Handler, mode: &str, krate: &ast::Crate) {
|
||||
let mode = match mode.parse().ok() {
|
||||
Some(mode) => mode,
|
||||
None => return,
|
||||
let Ok(mode) = mode.parse() else {
|
||||
return;
|
||||
};
|
||||
let mut v = ShowSpanVisitor { span_diagnostic, mode };
|
||||
visit::walk_crate(&mut v, krate);
|
||||
|
@ -714,7 +714,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
|
||||
token::NtLifetime(e) => e.to_string(),
|
||||
token::NtLiteral(ref e) => self.expr_to_string(e),
|
||||
token::NtTT(ref tree) => self.tt_to_string(tree),
|
||||
token::NtVis(ref e) => self.vis_to_string(e),
|
||||
}
|
||||
}
|
||||
|
@ -36,12 +36,16 @@ impl<'a> State<'a> {
|
||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
bounds,
|
||||
ty,
|
||||
}) => {
|
||||
self.print_associated_type(
|
||||
ident,
|
||||
generics,
|
||||
*where_clauses,
|
||||
*where_predicates_split,
|
||||
bounds,
|
||||
ty.as_deref(),
|
||||
vis,
|
||||
@ -95,11 +99,15 @@ impl<'a> State<'a> {
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
generics: &ast::Generics,
|
||||
where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
|
||||
where_predicates_split: usize,
|
||||
bounds: &ast::GenericBounds,
|
||||
ty: Option<&ast::Ty>,
|
||||
vis: &ast::Visibility,
|
||||
defaultness: ast::Defaultness,
|
||||
) {
|
||||
let (before_predicates, after_predicates) =
|
||||
generics.where_clause.predicates.split_at(where_predicates_split);
|
||||
self.head("");
|
||||
self.print_visibility(vis);
|
||||
self.print_defaultness(defaultness);
|
||||
@ -107,12 +115,13 @@ impl<'a> State<'a> {
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(&generics.params);
|
||||
self.print_type_bounds(":", bounds);
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.print_where_clause_parts(where_clauses.0.0, before_predicates);
|
||||
if let Some(ty) = ty {
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_type(ty);
|
||||
}
|
||||
self.print_where_clause_parts(where_clauses.1.0, after_predicates);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
@ -211,6 +220,8 @@ impl<'a> State<'a> {
|
||||
ast::ItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
ref generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
ref bounds,
|
||||
ref ty,
|
||||
}) => {
|
||||
@ -218,6 +229,8 @@ impl<'a> State<'a> {
|
||||
self.print_associated_type(
|
||||
item.ident,
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
bounds,
|
||||
ty,
|
||||
&item.vis,
|
||||
@ -496,10 +509,19 @@ impl<'a> State<'a> {
|
||||
ast::AssocItemKind::Const(def, ty, body) => {
|
||||
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
|
||||
}
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
bounds,
|
||||
ty,
|
||||
}) => {
|
||||
self.print_associated_type(
|
||||
ident,
|
||||
generics,
|
||||
*where_clauses,
|
||||
*where_predicates_split,
|
||||
bounds,
|
||||
ty.as_deref(),
|
||||
vis,
|
||||
@ -566,14 +588,22 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
|
||||
if where_clause.predicates.is_empty() && !where_clause.has_where_token {
|
||||
self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates);
|
||||
}
|
||||
|
||||
crate fn print_where_clause_parts(
|
||||
&mut self,
|
||||
has_where_token: bool,
|
||||
predicates: &[ast::WherePredicate],
|
||||
) {
|
||||
if predicates.is_empty() && !has_where_token {
|
||||
return;
|
||||
}
|
||||
|
||||
self.space();
|
||||
self.word_space("where");
|
||||
|
||||
for (i, predicate) in where_clause.predicates.iter().enumerate() {
|
||||
for (i, predicate) in predicates.iter().enumerate() {
|
||||
if i != 0 {
|
||||
self.word_space(",");
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
//! Parsing and validation of builtin attributes
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::node_id::CRATE_NODE_ID;
|
||||
use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_session::parse::{feature_err, ParseSess};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
@ -435,7 +435,12 @@ pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
||||
}
|
||||
|
||||
/// Tests if a cfg-pattern matches the cfg set
|
||||
pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
|
||||
pub fn cfg_matches(
|
||||
cfg: &ast::MetaItem,
|
||||
sess: &ParseSess,
|
||||
lint_node_id: NodeId,
|
||||
features: Option<&Features>,
|
||||
) -> bool {
|
||||
eval_condition(cfg, sess, features, &mut |cfg| {
|
||||
try_gate_cfg(cfg, sess, features);
|
||||
let error = |span, msg| {
|
||||
@ -461,29 +466,36 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
|
||||
true
|
||||
}
|
||||
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
|
||||
let name = cfg.ident().expect("multi-segment cfg predicate").name;
|
||||
let ident = cfg.ident().expect("multi-segment cfg predicate");
|
||||
let name = ident.name;
|
||||
let value = cfg.value_str();
|
||||
if sess.check_config.names_checked && !sess.check_config.names_valid.contains(&name)
|
||||
{
|
||||
sess.buffer_lint(
|
||||
if let Some(names_valid) = &sess.check_config.names_valid {
|
||||
if !names_valid.contains(&name) {
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
CRATE_NODE_ID,
|
||||
lint_node_id,
|
||||
"unexpected `cfg` condition name",
|
||||
BuiltinLintDiagnostics::UnexpectedCfg((name, ident.span), None),
|
||||
);
|
||||
}
|
||||
if let Some(val) = value {
|
||||
if sess.check_config.values_checked.contains(&name)
|
||||
&& !sess.check_config.values_valid.contains(&(name, val))
|
||||
{
|
||||
sess.buffer_lint(
|
||||
}
|
||||
if let Some(value) = value {
|
||||
if let Some(values) = &sess.check_config.values_valid.get(&name) {
|
||||
if !values.contains(&value) {
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
CRATE_NODE_ID,
|
||||
lint_node_id,
|
||||
"unexpected `cfg` condition value",
|
||||
BuiltinLintDiagnostics::UnexpectedCfg(
|
||||
(name, ident.span),
|
||||
Some((value, cfg.name_value_literal_span().unwrap())),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
sess.config.contains(&(name, value))
|
||||
}
|
||||
}
|
||||
@ -556,9 +568,7 @@ pub fn eval_condition(
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let min_version = match parse_version(min_version.as_str(), false) {
|
||||
Some(ver) => ver,
|
||||
None => {
|
||||
let Some(min_version) = parse_version(min_version.as_str(), false) else {
|
||||
sess.span_diagnostic
|
||||
.struct_span_warn(
|
||||
*span,
|
||||
@ -566,7 +576,6 @@ pub fn eval_condition(
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
|
||||
|
||||
@ -594,10 +603,18 @@ pub fn eval_condition(
|
||||
match cfg.name_or_empty() {
|
||||
sym::any => mis
|
||||
.iter()
|
||||
.any(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)),
|
||||
// We don't use any() here, because we want to evaluate all cfg condition
|
||||
// as eval_condition can (and does) extra checks
|
||||
.fold(false, |res, mi| {
|
||||
res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
||||
}),
|
||||
sym::all => mis
|
||||
.iter()
|
||||
.all(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)),
|
||||
// We don't use all() here, because we want to evaluate all cfg condition
|
||||
// as eval_condition can (and does) extra checks
|
||||
.fold(true, |res, mi| {
|
||||
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
||||
}),
|
||||
sym::not => {
|
||||
if mis.len() != 1 {
|
||||
struct_span_err!(
|
||||
@ -655,6 +672,7 @@ where
|
||||
{
|
||||
let mut depr: Option<(Deprecation, Span)> = None;
|
||||
let diagnostic = &sess.parse_sess.span_diagnostic;
|
||||
let is_rustc = sess.features_untracked().staged_api;
|
||||
|
||||
'outer: for attr in attrs_iter {
|
||||
if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) {
|
||||
@ -669,9 +687,8 @@ where
|
||||
break;
|
||||
}
|
||||
|
||||
let meta = match attr.meta() {
|
||||
Some(meta) => meta,
|
||||
None => continue,
|
||||
let Some(meta) = attr.meta() else {
|
||||
continue;
|
||||
};
|
||||
let mut since = None;
|
||||
let mut note = None;
|
||||
@ -720,17 +737,30 @@ where
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
sym::note if attr.has_name(sym::deprecated) => {
|
||||
sym::note => {
|
||||
if !get(mi, &mut note) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
// FIXME(jhpratt) remove this after a bootstrap occurs. Emitting an
|
||||
// error specific to the renaming would be a good idea as well.
|
||||
sym::reason if attr.has_name(sym::rustc_deprecated) => {
|
||||
if !get(mi, &mut note) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
sym::suggestion if attr.has_name(sym::rustc_deprecated) => {
|
||||
sym::suggestion => {
|
||||
if !sess.features_untracked().deprecated_suggestion {
|
||||
let mut diag = sess.struct_span_err(
|
||||
mi.span,
|
||||
"suggestions on deprecated items are unstable",
|
||||
);
|
||||
if sess.is_nightly_build() {
|
||||
diag.help("add `#![feature(deprecated_suggestion)]` to the crate root");
|
||||
}
|
||||
diag.note("see #94785 for more details").emit();
|
||||
}
|
||||
|
||||
if !get(mi, &mut suggestion) {
|
||||
continue 'outer;
|
||||
}
|
||||
@ -741,10 +771,10 @@ where
|
||||
meta.span(),
|
||||
AttrError::UnknownMetaItem(
|
||||
pprust::path_to_string(&mi.path),
|
||||
if attr.has_name(sym::deprecated) {
|
||||
&["since", "note"]
|
||||
if sess.features_untracked().deprecated_suggestion {
|
||||
&["since", "note", "suggestion"]
|
||||
} else {
|
||||
&["since", "reason", "suggestion"]
|
||||
&["since", "note"]
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -767,24 +797,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if suggestion.is_some() && attr.has_name(sym::deprecated) {
|
||||
unreachable!("only allowed on rustc_deprecated")
|
||||
}
|
||||
|
||||
if attr.has_name(sym::rustc_deprecated) {
|
||||
if is_rustc {
|
||||
if since.is_none() {
|
||||
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
|
||||
continue;
|
||||
}
|
||||
|
||||
if note.is_none() {
|
||||
struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
|
||||
struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let is_since_rustc_version = attr.has_name(sym::rustc_deprecated);
|
||||
depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span));
|
||||
depr = Some((
|
||||
Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
|
||||
attr.span,
|
||||
));
|
||||
}
|
||||
|
||||
depr
|
||||
|
@ -8,7 +8,7 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
either = "1.5.0"
|
||||
itertools = "0.10"
|
||||
itertools = "0.10.1"
|
||||
tracing = "0.1"
|
||||
polonius-engine = "0.13.0"
|
||||
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
|
||||
|
@ -1,9 +1,13 @@
|
||||
use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId};
|
||||
use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
|
||||
impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
crate fn cannot_move_when_borrowed(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> {
|
||||
crate fn cannot_move_when_borrowed(
|
||||
&self,
|
||||
span: Span,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,)
|
||||
}
|
||||
|
||||
@ -13,7 +17,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desc: &str,
|
||||
borrow_span: Span,
|
||||
borrow_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
span,
|
||||
@ -32,7 +36,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
verb: &str,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(
|
||||
self,
|
||||
span,
|
||||
@ -51,7 +55,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
old_loan_span: Span,
|
||||
old_opt_via: &str,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let via =
|
||||
|msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
|
||||
let mut err = struct_span_err!(
|
||||
@ -99,7 +103,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desc: &str,
|
||||
old_loan_span: Span,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
new_loan_span,
|
||||
@ -132,7 +136,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
noun_old: &str,
|
||||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
new_loan_span,
|
||||
@ -164,7 +168,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
second_borrow_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
new_loan_span,
|
||||
@ -200,7 +204,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
kind_old: &str,
|
||||
msg_old: &str,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let via =
|
||||
|msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
|
||||
let mut err = struct_span_err!(
|
||||
@ -243,7 +247,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
borrow_span: Span,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
span,
|
||||
@ -262,12 +266,16 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
desc: &str,
|
||||
is_arg: bool,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
|
||||
struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc)
|
||||
}
|
||||
|
||||
crate fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> {
|
||||
crate fn cannot_assign(
|
||||
&self,
|
||||
span: Span,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
|
||||
}
|
||||
|
||||
@ -275,7 +283,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
move_from_span: Span,
|
||||
move_from_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,)
|
||||
}
|
||||
|
||||
@ -287,7 +295,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
move_from_span: Span,
|
||||
ty: Ty<'_>,
|
||||
is_index: Option<bool>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let type_name = match (&ty.kind(), is_index) {
|
||||
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
||||
(&ty::Slice(_), _) => "slice",
|
||||
@ -309,7 +317,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
move_from_span: Span,
|
||||
container_ty: Ty<'_>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
move_from_span,
|
||||
@ -327,7 +335,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
verb: &str,
|
||||
optional_adverb_for_moved: &str,
|
||||
moved_path: Option<String>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default();
|
||||
|
||||
struct_span_err!(
|
||||
@ -346,7 +354,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
path: &str,
|
||||
reason: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
|
||||
}
|
||||
|
||||
@ -357,7 +365,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
immutable_place: &str,
|
||||
immutable_section: &str,
|
||||
action: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
mutate_span,
|
||||
@ -376,7 +384,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
span: Span,
|
||||
yield_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
span,
|
||||
@ -387,7 +395,10 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
err
|
||||
}
|
||||
|
||||
crate fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> DiagnosticBuilder<'cx> {
|
||||
crate fn cannot_borrow_across_destructor(
|
||||
&self,
|
||||
borrow_span: Span,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(
|
||||
self,
|
||||
borrow_span,
|
||||
@ -400,7 +411,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
span: Span,
|
||||
path: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
|
||||
}
|
||||
|
||||
@ -410,7 +421,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return_kind: &str,
|
||||
reference_desc: &str,
|
||||
path_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
span,
|
||||
@ -435,7 +446,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
closure_kind: &str,
|
||||
borrowed_path: &str,
|
||||
capture_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
closure_span,
|
||||
@ -454,11 +465,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
crate fn thread_local_value_does_not_live_long_enough(
|
||||
&self,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
|
||||
}
|
||||
|
||||
crate fn temporary_value_borrowed_for_too_long(&self, span: Span) -> DiagnosticBuilder<'cx> {
|
||||
crate fn temporary_value_borrowed_for_too_long(
|
||||
&self,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
|
||||
}
|
||||
|
||||
@ -467,7 +481,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code)
|
||||
}
|
||||
}
|
||||
@ -476,7 +490,7 @@ crate fn borrowed_data_escapes_closure<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
escape_span: Span,
|
||||
escapes_from: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
escape_span,
|
||||
|
@ -407,10 +407,10 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||
fn terminator_effect(
|
||||
&self,
|
||||
trans: &mut impl GenKill<Self::Idx>,
|
||||
teminator: &mir::Terminator<'tcx>,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
if let mir::TerminatorKind::InlineAsm { operands, .. } = &teminator.kind {
|
||||
if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind {
|
||||
for op in operands {
|
||||
if let mir::InlineAsmOperand::Out { place: Some(place), .. }
|
||||
| mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op
|
||||
|
@ -1,10 +1,14 @@
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc_infer::infer::region_constraints::Constraint;
|
||||
use rustc_infer::infer::region_constraints::RegionConstraintData;
|
||||
use rustc_infer::infer::RegionVariableOrigin;
|
||||
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
|
||||
use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use rustc_middle::ty::UniverseIndex;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::type_op;
|
||||
@ -76,6 +80,15 @@ crate trait ToUniverseInfo<'tcx> {
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
|
||||
base_universe: Some(base_universe),
|
||||
..self
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
|
||||
{
|
||||
@ -116,21 +129,31 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToUniverseInfo<'tcx> for ! {
|
||||
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
trait TypeOpInfo<'tcx> {
|
||||
/// Returns an error to be reported if rerunning the type op fails to
|
||||
/// recover the error's cause.
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>>;
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
|
||||
|
||||
fn report_error(
|
||||
&self,
|
||||
@ -171,7 +194,7 @@ trait TypeOpInfo<'tcx> {
|
||||
debug!(?placeholder_region);
|
||||
|
||||
let span = cause.span;
|
||||
let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
|
||||
let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
|
||||
|
||||
if let Some(nice_error) = nice_error {
|
||||
mbcx.buffer_error(nice_error);
|
||||
@ -188,7 +211,11 @@ struct PredicateQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
|
||||
err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
|
||||
err
|
||||
@ -200,16 +227,16 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
|
||||
cause.span,
|
||||
&self.canonical_query,
|
||||
|ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
|
||||
try_extract_error_from_fulfill_cx(
|
||||
fulfill_cx,
|
||||
@ -231,7 +258,11 @@ impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
|
||||
where
|
||||
T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
|
||||
{
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
|
||||
err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
|
||||
err
|
||||
@ -243,16 +274,16 @@ where
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
|
||||
cause.span,
|
||||
&self.canonical_query,
|
||||
|ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
|
||||
let mut selcx = SelectionContext::new(infcx);
|
||||
|
||||
@ -288,7 +319,11 @@ struct AscribeUserTypeQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
|
||||
@ -300,16 +335,16 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
|
||||
cause.span,
|
||||
&self.canonical_query,
|
||||
|ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
|
||||
.ok()?;
|
||||
try_extract_error_from_fulfill_cx(
|
||||
@ -323,22 +358,74 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
||||
fn fallback_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!")
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
self.base_universe.unwrap()
|
||||
}
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
_cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
try_extract_error_from_region_constraints(
|
||||
mbcx.infcx,
|
||||
placeholder_region,
|
||||
error_region,
|
||||
self.region_constraints.as_ref().unwrap(),
|
||||
// We're using the original `InferCtxt` that we
|
||||
// started MIR borrowchecking with, so the region
|
||||
// constraints have already been taken. Use the data from
|
||||
// our `mbcx` instead.
|
||||
|vid| mbcx.regioncx.var_infos[vid].origin,
|
||||
|vid| mbcx.regioncx.var_infos[vid].universe,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(fulfill_cx, infcx), level = "debug")]
|
||||
fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
// 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);
|
||||
let region_constraints = infcx.with_region_constraints(|r| r.clone());
|
||||
try_extract_error_from_region_constraints(
|
||||
infcx,
|
||||
placeholder_region,
|
||||
error_region,
|
||||
®ion_constraints,
|
||||
|vid| infcx.region_var_origin(vid),
|
||||
|vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
|
||||
)
|
||||
}
|
||||
|
||||
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
|
||||
debug!("{:#?}", region_constraints);
|
||||
fn try_extract_error_from_region_constraints<'tcx>(
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
region_constraints: &RegionConstraintData<'tcx>,
|
||||
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
|
||||
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
let (sub_region, cause) =
|
||||
region_constraints.constraints.iter().find_map(|(constraint, cause)| {
|
||||
match *constraint {
|
||||
Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
|
||||
@ -346,11 +433,10 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
}
|
||||
// FIXME: Should this check the universe of the var?
|
||||
Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
|
||||
Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
|
||||
Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})?;
|
||||
|
||||
debug!(?sub_region, "cause = {:#?}", cause);
|
||||
@ -359,7 +445,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
infcx,
|
||||
RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
infcx.region_var_origin(vid),
|
||||
region_var_origin(vid),
|
||||
cause.clone(),
|
||||
error_region,
|
||||
cause.clone(),
|
||||
@ -376,8 +462,8 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
infcx,
|
||||
RegionResolutionError::UpperBoundUniverseConflict(
|
||||
vid,
|
||||
infcx.region_var_origin(vid),
|
||||
infcx.universe_of_region(sub_region),
|
||||
region_var_origin(vid),
|
||||
universe_of_region(vid),
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
),
|
||||
|
@ -1,20 +1,23 @@
|
||||
use either::Either;
|
||||
use rustc_const_eval::util::{CallDesugaringKind, CallKind};
|
||||
use rustc_const_eval::util::CallKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
|
||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
|
||||
use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
|
||||
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_span::{BytePos, MultiSpan, Span};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::TraitEngineExt as _;
|
||||
|
||||
use crate::borrow_set::TwoPhaseActivation;
|
||||
use crate::borrowck_errors;
|
||||
@ -148,6 +151,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
.args_or_use()
|
||||
})
|
||||
.collect::<Vec<Span>>();
|
||||
|
||||
let reinits = maybe_reinitialized_locations.len();
|
||||
if reinits == 1 {
|
||||
err.span_label(reinit_spans[0], "this reinitialization might get skipped");
|
||||
@ -190,144 +194,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
is_loop_move = true;
|
||||
}
|
||||
|
||||
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
|
||||
let place_name = self
|
||||
.describe_place(moved_place.as_ref())
|
||||
.map(|n| format!("`{}`", n))
|
||||
.unwrap_or_else(|| "value".to_owned());
|
||||
match kind {
|
||||
CallKind::FnCall { fn_trait_id, .. }
|
||||
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
||||
{
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this call{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
err.span_note(
|
||||
var_span,
|
||||
"this value implements `FnOnce`, which causes it to be moved when called",
|
||||
);
|
||||
}
|
||||
CallKind::Operator { self_arg, .. } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to usage in operator{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
err.span_note(
|
||||
// Check whether the source is accessible
|
||||
if self
|
||||
.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(self_arg.span)
|
||||
.is_ok()
|
||||
{
|
||||
self_arg.span
|
||||
} else {
|
||||
fn_call_span
|
||||
},
|
||||
"calling this operator moves the left-hand side",
|
||||
);
|
||||
}
|
||||
}
|
||||
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this implicit call to `.into_iter()`{}",
|
||||
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,
|
||||
&format!(
|
||||
"{} {}moved due to this method call{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
}
|
||||
if is_option_or_result && maybe_reinitialized_locations.is_empty() {
|
||||
err.span_suggestion_verbose(
|
||||
fn_call_span.shrink_to_lo(),
|
||||
"consider calling `.as_ref()` to borrow the type's contents",
|
||||
"as_ref().".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// Avoid pointing to the same function in multiple different
|
||||
// error messages.
|
||||
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
|
||||
{
|
||||
err.span_note(
|
||||
self_arg.span,
|
||||
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
|
||||
);
|
||||
}
|
||||
}
|
||||
// Other desugarings takes &self, which cannot cause a move
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
err.span_label(
|
||||
move_span,
|
||||
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
|
||||
);
|
||||
// If the move error occurs due to a loop, don't show
|
||||
// another message for the same span
|
||||
if loop_message.is_empty() {
|
||||
move_spans.var_span_label(
|
||||
self.explain_captures(
|
||||
&mut err,
|
||||
format!(
|
||||
"variable {}moved due to use{}",
|
||||
span,
|
||||
move_span,
|
||||
move_spans,
|
||||
*moved_place,
|
||||
Some(used_place),
|
||||
partially_str,
|
||||
move_spans.describe()
|
||||
),
|
||||
"moved",
|
||||
loop_message,
|
||||
move_msg,
|
||||
is_loop_move,
|
||||
maybe_reinitialized_locations.is_empty(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let (UseSpans::PatUse(span), []) =
|
||||
(move_spans, &maybe_reinitialized_locations[..])
|
||||
@ -398,35 +277,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if needs_note {
|
||||
let opt_name =
|
||||
self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
|
||||
let note_msg = match opt_name {
|
||||
Some(ref name) => format!("`{}`", name),
|
||||
None => "value".to_owned(),
|
||||
};
|
||||
if let ty::Param(param_ty) = ty.kind() {
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
let param = generics.type_param(¶m_ty, tcx);
|
||||
if let Some(generics) = tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
||||
{
|
||||
suggest_constraining_type_param(
|
||||
tcx,
|
||||
generics,
|
||||
&mut err,
|
||||
param.name.as_str(),
|
||||
"Copy",
|
||||
None,
|
||||
);
|
||||
}
|
||||
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) {
|
||||
// Suppress the next suggestion since we don't want to put more bounds onto
|
||||
// something that already has `Fn`-like bounds (or is a closure), so we can't
|
||||
// restrict anyways.
|
||||
} else {
|
||||
self.suggest_adding_copy_bounds(&mut err, ty, span);
|
||||
}
|
||||
|
||||
if needs_note {
|
||||
let span = if let Some(local) = place.as_local() {
|
||||
let decl = &self.body.local_decls[local];
|
||||
Some(decl.source_info.span)
|
||||
Some(self.body.local_decls[local].source_info.span)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -454,6 +321,144 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_borrow_fn_like(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
ty: Ty<'tcx>,
|
||||
move_sites: &[MoveSite],
|
||||
value_name: &str,
|
||||
) -> bool {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
// Find out if the predicates show that the type is a Fn or FnMut
|
||||
let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| {
|
||||
predicates.iter().find_map(|(pred, _)| {
|
||||
let pred = if let Some(substs) = substs {
|
||||
pred.subst(tcx, substs).kind().skip_binder()
|
||||
} else {
|
||||
pred.kind().skip_binder()
|
||||
};
|
||||
if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
|
||||
if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
|
||||
return Some(hir::Mutability::Not);
|
||||
} else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
|
||||
return Some(hir::Mutability::Mut);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
};
|
||||
|
||||
// If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
|
||||
// borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
|
||||
// These types seem reasonably opaque enough that they could be substituted with their
|
||||
// borrowed variants in a function body when we see a move error.
|
||||
let borrow_level = match ty.kind() {
|
||||
ty::Param(_) => find_fn_kind_from_did(
|
||||
tcx.explicit_predicates_of(self.mir_def_id().to_def_id()).predicates,
|
||||
None,
|
||||
),
|
||||
ty::Opaque(did, substs) => {
|
||||
find_fn_kind_from_did(tcx.explicit_item_bounds(*did), Some(*substs))
|
||||
}
|
||||
ty::Closure(_, substs) => match substs.as_closure().kind() {
|
||||
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
|
||||
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let Some(borrow_level) = borrow_level else { return false; };
|
||||
let sugg = move_sites
|
||||
.iter()
|
||||
.map(|move_site| {
|
||||
let move_out = self.move_data.moves[(*move_site).moi];
|
||||
let moved_place = &self.move_data.move_paths[move_out.path].place;
|
||||
let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
|
||||
let move_span = move_spans.args_or_use();
|
||||
let suggestion = if borrow_level == hir::Mutability::Mut {
|
||||
"&mut ".to_string()
|
||||
} else {
|
||||
"&".to_string()
|
||||
};
|
||||
(move_span.shrink_to_lo(), suggestion)
|
||||
})
|
||||
.collect();
|
||||
err.multipart_suggestion_verbose(
|
||||
&format!(
|
||||
"consider {}borrowing {value_name}",
|
||||
if borrow_level == hir::Mutability::Mut { "mutably " } else { "" }
|
||||
),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
fn suggest_adding_copy_bounds(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
|
||||
let Some(hir_generics) = tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
||||
else { return; };
|
||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||
let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
|
||||
|
||||
let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
|
||||
let cause = ObligationCause::new(
|
||||
span,
|
||||
self.mir_hir_id(),
|
||||
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
||||
);
|
||||
fulfill_cx.register_bound(
|
||||
&infcx,
|
||||
self.param_env,
|
||||
// Erase any region vids from the type, which may not be resolved
|
||||
infcx.tcx.erase_regions(ty),
|
||||
copy_did,
|
||||
cause,
|
||||
);
|
||||
// Select all, including ambiguous predicates
|
||||
let errors = fulfill_cx.select_all_or_error(&infcx);
|
||||
|
||||
// Only emit suggestion if all required predicates are on generic
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|err| match err.obligation.predicate.kind().skip_binder() {
|
||||
PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
|
||||
ty::Param(param_ty) => Ok((
|
||||
generics.type_param(param_ty, tcx),
|
||||
predicate.trait_ref.print_only_trait_path().to_string(),
|
||||
)),
|
||||
_ => Err(()),
|
||||
},
|
||||
_ => Err(()),
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
if let Ok(predicates) = predicates {
|
||||
suggest_constraining_type_params(
|
||||
tcx,
|
||||
hir_generics,
|
||||
err,
|
||||
predicates
|
||||
.iter()
|
||||
.map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn report_move_out_while_borrowed(
|
||||
&mut self,
|
||||
location: Location,
|
||||
@ -507,7 +512,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
location: Location,
|
||||
(place, _span): (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.args_or_use();
|
||||
|
||||
@ -554,7 +559,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
gen_borrow_kind: BorrowKind,
|
||||
issued_borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
|
||||
let issued_span = issued_spans.args_or_use();
|
||||
|
||||
@ -782,7 +787,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self, err))]
|
||||
fn suggest_using_local_if_applicable(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
location: Location,
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
gen_borrow_kind: BorrowKind,
|
||||
@ -855,7 +860,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
fn suggest_split_at_mut_if_applicable(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
place: Place<'tcx>,
|
||||
borrowed_place: Place<'tcx>,
|
||||
) {
|
||||
@ -1120,7 +1125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
drop_span: Span,
|
||||
borrow_spans: UseSpans<'tcx>,
|
||||
explanation: BorrowExplanation,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
debug!(
|
||||
"report_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}, {:?}\
|
||||
@ -1298,7 +1303,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&mut self,
|
||||
drop_span: Span,
|
||||
borrow_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
debug!(
|
||||
"report_thread_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}\
|
||||
@ -1325,7 +1330,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
borrow_spans: UseSpans<'tcx>,
|
||||
proper_span: Span,
|
||||
explanation: BorrowExplanation,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
debug!(
|
||||
"report_temporary_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}\
|
||||
@ -1384,7 +1389,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return_span: Span,
|
||||
category: ConstraintCategory,
|
||||
opt_place_desc: Option<&String>,
|
||||
) -> Option<DiagnosticBuilder<'cx>> {
|
||||
) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
|
||||
let return_kind = match category {
|
||||
ConstraintCategory::Return(_) => "return",
|
||||
ConstraintCategory::Yield => "yield",
|
||||
@ -1483,7 +1488,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
category: ConstraintCategory,
|
||||
constraint_span: Span,
|
||||
captured_var: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let args_span = use_span.args_or_use();
|
||||
|
||||
@ -1560,7 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
upvar_span: Span,
|
||||
upvar_name: &str,
|
||||
escape_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id());
|
||||
@ -1835,7 +1840,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
|
||||
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
|
||||
let tcx = self.infcx.tcx;
|
||||
if let (
|
||||
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
|
||||
@ -1921,9 +1926,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
err.span_label(assigned_span, format!("first assignment to {}", place_description));
|
||||
}
|
||||
}
|
||||
if let Some(decl) = local_decl {
|
||||
if let Some(name) = local_name {
|
||||
if decl.can_be_made_mutable() {
|
||||
if let Some(decl) = local_decl
|
||||
&& let Some(name) = local_name
|
||||
&& decl.can_be_made_mutable()
|
||||
{
|
||||
err.span_suggestion(
|
||||
decl.source_info.span,
|
||||
"consider making this binding mutable",
|
||||
@ -1931,8 +1937,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
err.span_label(span, msg);
|
||||
self.buffer_error(err);
|
||||
}
|
||||
@ -2071,11 +2075,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
) = rvalue
|
||||
{
|
||||
for operand in operands {
|
||||
let assigned_from = match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
|
||||
continue;
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
@ -2083,10 +2084,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
// Find the local from the operand.
|
||||
let assigned_from_local = match assigned_from.local_or_deref_local()
|
||||
{
|
||||
Some(local) => local,
|
||||
None => continue,
|
||||
let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if assigned_from_local != target {
|
||||
@ -2138,10 +2137,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
// Find the local from the rvalue.
|
||||
let assigned_from_local = match assigned_from.local_or_deref_local() {
|
||||
Some(local) => local,
|
||||
None => continue,
|
||||
};
|
||||
let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { continue };
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?}",
|
||||
@ -2189,11 +2185,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
assigned_to, args
|
||||
);
|
||||
for operand in args {
|
||||
let assigned_from = match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
|
||||
continue;
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
@ -2309,7 +2302,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// Closure arguments are wrapped in a tuple, so we need to get the first
|
||||
// from that.
|
||||
if let ty::Tuple(elems) = argument_ty.kind() {
|
||||
let argument_ty = elems.first()?.expect_ty();
|
||||
let &argument_ty = elems.first()?;
|
||||
if let ty::Ref(_, _, _) = argument_ty.kind() {
|
||||
return Some(AnnotatedBorrowFnSignature::Closure {
|
||||
argument_ty,
|
||||
@ -2373,11 +2366,7 @@ enum AnnotatedBorrowFnSignature<'tcx> {
|
||||
impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
|
||||
/// Annotate the provided diagnostic with information about borrow from the fn signature that
|
||||
/// helps explain.
|
||||
pub(crate) fn emit(
|
||||
&self,
|
||||
cx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
diag: &mut DiagnosticBuilder<'_>,
|
||||
) -> String {
|
||||
pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String {
|
||||
match self {
|
||||
&AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
|
||||
diag.span_label(
|
||||
|
@ -3,7 +3,7 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::mir::{
|
||||
@ -60,7 +60,7 @@ impl BorrowExplanation {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
borrow_desc: &str,
|
||||
borrow_span: Option<Span>,
|
||||
multiple_borrow_span: Option<(Span, Span)>,
|
||||
@ -138,7 +138,7 @@ impl BorrowExplanation {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
@ -148,7 +148,7 @@ impl BorrowExplanation {
|
||||
// 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() => {
|
||||
("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did)))
|
||||
("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did())))
|
||||
}
|
||||
|
||||
// Otherwise, just report the whole type (and use
|
||||
@ -275,7 +275,7 @@ impl BorrowExplanation {
|
||||
}
|
||||
pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
category: &ConstraintCategory,
|
||||
span: Span,
|
||||
region_name: &RegionName,
|
||||
@ -375,16 +375,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
Some(Cause::DropVar(local, location)) => {
|
||||
let mut should_note_order = false;
|
||||
if self.local_names[local].is_some() {
|
||||
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
||||
if let Some(borrowed_local) = place.as_local() {
|
||||
if self.local_names[borrowed_local].is_some() && local != borrowed_local
|
||||
if self.local_names[local].is_some()
|
||||
&& let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
|
||||
&& let Some(borrowed_local) = place.as_local()
|
||||
&& self.local_names[borrowed_local].is_some() && local != borrowed_local
|
||||
{
|
||||
should_note_order = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BorrowExplanation::UsedLaterWhenDropped {
|
||||
drop_loc: location,
|
||||
@ -650,13 +647,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
// The only kind of statement that we care about is assignments...
|
||||
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
|
||||
let into = match place.local_or_deref_local() {
|
||||
Some(into) => into,
|
||||
None => {
|
||||
let Some(into) = place.local_or_deref_local() else {
|
||||
// Continue at the next location.
|
||||
queue.push(current_location.successor_within_block());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match rvalue {
|
||||
|
@ -1,11 +1,12 @@
|
||||
//! Borrow checker diagnostics.
|
||||
|
||||
use rustc_const_eval::util::call_kind;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_const_eval::util::{call_kind, CallDesugaringKind};
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GeneratorKind;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::{
|
||||
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
|
||||
Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
@ -13,8 +14,9 @@ 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::{symbol::sym, Span};
|
||||
use rustc_span::{symbol::sym, Span, DUMMY_SP};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
|
||||
|
||||
use super::borrow_set::BorrowData;
|
||||
use super::MirBorrowckCtxt;
|
||||
@ -57,7 +59,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
location: Location,
|
||||
place: PlaceRef<'tcx>,
|
||||
diag: &mut DiagnosticBuilder<'_>,
|
||||
diag: &mut Diagnostic,
|
||||
) {
|
||||
debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
|
||||
let mut target = place.local_or_deref_local();
|
||||
@ -368,7 +370,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
ty::Adt(def, _) => {
|
||||
let variant = if let Some(idx) = variant_index {
|
||||
assert!(def.is_enum());
|
||||
&def.variants[idx]
|
||||
&def.variant(idx)
|
||||
} else {
|
||||
def.non_enum_variant()
|
||||
};
|
||||
@ -409,7 +411,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// Add a note that a type does not implement `Copy`
|
||||
pub(super) fn note_type_does_not_implement_copy(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
place_desc: &str,
|
||||
ty: Ty<'tcx>,
|
||||
span: Option<Span>,
|
||||
@ -444,10 +446,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
debug!("borrowed_content_source: init={:?}", init);
|
||||
// We're only interested in statements that initialized a value, not the
|
||||
// initializations from arguments.
|
||||
let loc = match init.location {
|
||||
InitLocation::Statement(stmt) => stmt,
|
||||
_ => continue,
|
||||
};
|
||||
let InitLocation::Statement(loc) = init.location else { continue };
|
||||
|
||||
let bbd = &self.body[loc.block];
|
||||
let is_terminator = bbd.statements.len() == loc.statement_index;
|
||||
@ -485,14 +484,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
BorrowedContentSource::DerefSharedRef
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
|
||||
/// name where required.
|
||||
pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
|
||||
let mut s = String::new();
|
||||
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
|
||||
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
||||
|
||||
// We need to add synthesized lifetimes where appropriate. We do
|
||||
// this by hooking into the pretty printer and telling it to label the
|
||||
@ -507,15 +503,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let _ = ty.print(printer);
|
||||
s
|
||||
ty.print(printer).unwrap().into_buffer()
|
||||
}
|
||||
|
||||
/// Returns the name of the provided `Ty` (that must be a reference)'s region with a
|
||||
/// synthesized lifetime name where required.
|
||||
pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
|
||||
let mut s = String::new();
|
||||
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
|
||||
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
||||
|
||||
let region = if let ty::Ref(region, ..) = ty.kind() {
|
||||
match **region {
|
||||
@ -530,8 +524,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
bug!("ty for annotation of borrow region is not a reference");
|
||||
};
|
||||
|
||||
let _ = region.print(printer);
|
||||
s
|
||||
region.print(printer).unwrap().into_buffer()
|
||||
}
|
||||
}
|
||||
|
||||
@ -616,11 +609,7 @@ impl UseSpans<'_> {
|
||||
}
|
||||
|
||||
// Add a span label to the arguments of the closure, if it exists.
|
||||
pub(super) fn args_span_label(
|
||||
self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
message: impl Into<String>,
|
||||
) {
|
||||
pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) {
|
||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||
err.span_label(args_span, message);
|
||||
}
|
||||
@ -628,11 +617,7 @@ impl UseSpans<'_> {
|
||||
|
||||
// Add a span label to the use of the captured variable, if it exists.
|
||||
// only adds label to the `path_span`
|
||||
pub(super) fn var_span_label_path_only(
|
||||
self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
message: impl Into<String>,
|
||||
) {
|
||||
pub(super) fn var_span_label_path_only(self, err: &mut Diagnostic, message: impl Into<String>) {
|
||||
if let UseSpans::ClosureUse { path_span, .. } = self {
|
||||
err.span_label(path_span, message);
|
||||
}
|
||||
@ -641,7 +626,7 @@ impl UseSpans<'_> {
|
||||
// Add a span label to the use of the captured variable, if it exists.
|
||||
pub(super) fn var_span_label(
|
||||
self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
message: impl Into<String>,
|
||||
kind_desc: impl Into<String>,
|
||||
) {
|
||||
@ -716,7 +701,7 @@ impl<'tcx> BorrowedContentSource<'tcx> {
|
||||
BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
|
||||
BorrowedContentSource::OverloadedDeref(ty) => ty
|
||||
.ty_adt_def()
|
||||
.and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
|
||||
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
|
||||
name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
|
||||
_ => None,
|
||||
})
|
||||
@ -746,7 +731,7 @@ impl<'tcx> BorrowedContentSource<'tcx> {
|
||||
}
|
||||
BorrowedContentSource::OverloadedDeref(ty) => ty
|
||||
.ty_adt_def()
|
||||
.and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
|
||||
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
|
||||
name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
|
||||
_ => None,
|
||||
})
|
||||
@ -787,9 +772,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
) -> UseSpans<'tcx> {
|
||||
use self::UseSpans::*;
|
||||
|
||||
let stmt = match self.body[location.block].statements.get(location.statement_index) {
|
||||
Some(stmt) => stmt,
|
||||
None => return OtherUse(self.body.source_info(location).span),
|
||||
let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else {
|
||||
return OtherUse(self.body.source_info(location).span);
|
||||
};
|
||||
|
||||
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
||||
@ -1011,4 +995,173 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let span = self.body.source_info(borrow.reserve_location).span;
|
||||
self.borrow_spans(span, borrow.reserve_location)
|
||||
}
|
||||
|
||||
fn explain_captures(
|
||||
&mut self,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
move_span: Span,
|
||||
move_spans: UseSpans<'tcx>,
|
||||
moved_place: Place<'tcx>,
|
||||
used_place: Option<PlaceRef<'tcx>>,
|
||||
partially_str: &str,
|
||||
loop_message: &str,
|
||||
move_msg: &str,
|
||||
is_loop_move: bool,
|
||||
maybe_reinitialized_locations_is_empty: bool,
|
||||
) {
|
||||
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
|
||||
let place_name = self
|
||||
.describe_place(moved_place.as_ref())
|
||||
.map(|n| format!("`{}`", n))
|
||||
.unwrap_or_else(|| "value".to_owned());
|
||||
match kind {
|
||||
CallKind::FnCall { fn_trait_id, .. }
|
||||
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
||||
{
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this call{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
err.span_note(
|
||||
var_span,
|
||||
"this value implements `FnOnce`, which causes it to be moved when called",
|
||||
);
|
||||
}
|
||||
CallKind::Operator { self_arg, .. } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to usage in operator{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
err.span_note(
|
||||
// Check whether the source is accessible
|
||||
if self
|
||||
.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(self_arg.span)
|
||||
.is_ok()
|
||||
{
|
||||
self_arg.span
|
||||
} else {
|
||||
fn_call_span
|
||||
},
|
||||
"calling this operator moves the left-hand side",
|
||||
);
|
||||
}
|
||||
}
|
||||
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
||||
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(
|
||||
&infcx,
|
||||
self.param_env,
|
||||
infcx.tcx.mk_imm_ref(
|
||||
infcx.tcx.lifetimes.re_erased,
|
||||
infcx.tcx.erase_regions(ty),
|
||||
),
|
||||
def_id,
|
||||
DUMMY_SP,
|
||||
)
|
||||
}),
|
||||
_ => false,
|
||||
};
|
||||
if suggest {
|
||||
err.span_suggestion_verbose(
|
||||
move_span.shrink_to_lo(),
|
||||
&format!(
|
||||
"consider iterating over a slice of the `{}`'s content to \
|
||||
avoid moving into the `for` loop",
|
||||
ty,
|
||||
),
|
||||
"&".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this implicit call to `.into_iter()`{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
// If we have a `&mut` ref, we need to reborrow.
|
||||
if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
|
||||
.map(|used_place| used_place.ty(self.body, self.infcx.tcx).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 {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this method call{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
}
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.span_suggestion_verbose(
|
||||
fn_call_span.shrink_to_lo(),
|
||||
"consider calling `.as_ref()` to borrow the type's contents",
|
||||
"as_ref().".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// Avoid pointing to the same function in multiple different
|
||||
// error messages.
|
||||
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
|
||||
err.span_note(
|
||||
self_arg.span,
|
||||
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
|
||||
);
|
||||
}
|
||||
}
|
||||
// Other desugarings takes &self, which cannot cause a move
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
if move_span != span || !loop_message.is_empty() {
|
||||
err.span_label(
|
||||
move_span,
|
||||
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
|
||||
);
|
||||
}
|
||||
// If the move error occurs due to a loop, don't show
|
||||
// another message for the same span
|
||||
if loop_message.is_empty() {
|
||||
move_spans.var_span_label(
|
||||
err,
|
||||
format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
|
||||
"moved",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
use rustc_const_eval::util::CallDesugaringKind;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty;
|
||||
use rustc_mir_dataflow::move_paths::{
|
||||
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
|
||||
};
|
||||
use rustc_span::{sym, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use crate::diagnostics::{CallKind, UseSpans};
|
||||
use crate::diagnostics::UseSpans;
|
||||
use crate::prefixes::PrefixSet;
|
||||
use crate::MirBorrowckCtxt;
|
||||
|
||||
@ -188,10 +185,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
// Error with the pattern
|
||||
LookupResult::Exact(_) => {
|
||||
let mpi = match self.move_data.rev_lookup.find(move_from.as_ref()) {
|
||||
LookupResult::Parent(Some(mpi)) => mpi,
|
||||
let LookupResult::Parent(Some(mpi)) = self.move_data.rev_lookup.find(move_from.as_ref()) else {
|
||||
// move_from should be a projection from match_place.
|
||||
_ => unreachable!("Probably not unreachable..."),
|
||||
unreachable!("Probably not unreachable...");
|
||||
};
|
||||
for ge in &mut *grouped_errors {
|
||||
if let GroupedMoveError::MovesFromValue {
|
||||
@ -222,18 +218,29 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
fn report(&mut self, error: GroupedMoveError<'tcx>) {
|
||||
let (mut err, err_span) = {
|
||||
let (span, use_spans, original_path, kind): (
|
||||
let (span, use_spans, original_path, kind, has_complex_bindings): (
|
||||
Span,
|
||||
Option<UseSpans<'tcx>>,
|
||||
Place<'tcx>,
|
||||
&IllegalMoveOriginKind<'_>,
|
||||
bool,
|
||||
) = match error {
|
||||
GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
|
||||
| GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
|
||||
(span, None, original_path, kind)
|
||||
GroupedMoveError::MovesFromPlace {
|
||||
span,
|
||||
original_path,
|
||||
ref kind,
|
||||
ref binds_to,
|
||||
..
|
||||
}
|
||||
| GroupedMoveError::MovesFromValue {
|
||||
span,
|
||||
original_path,
|
||||
ref kind,
|
||||
ref binds_to,
|
||||
..
|
||||
} => (span, None, original_path, kind, !binds_to.is_empty()),
|
||||
GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
|
||||
(use_spans.args_or_use(), Some(use_spans), original_path, kind)
|
||||
(use_spans.args_or_use(), Some(use_spans), original_path, kind, false)
|
||||
}
|
||||
};
|
||||
debug!(
|
||||
@ -252,6 +259,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
target_place,
|
||||
span,
|
||||
use_spans,
|
||||
has_complex_bindings,
|
||||
),
|
||||
&IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
||||
self.cannot_move_out_of_interior_of_drop(span, ty)
|
||||
@ -272,7 +280,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
&mut self,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let description = if place.projection.len() == 1 {
|
||||
format!("static item {}", self.describe_any_place(place.as_ref()))
|
||||
} else {
|
||||
@ -294,7 +302,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
deref_target_place: Place<'tcx>,
|
||||
span: Span,
|
||||
use_spans: Option<UseSpans<'tcx>>,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
has_complex_bindings: bool,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
// Inspect the type of the content behind the
|
||||
// borrow to provide feedback about why this
|
||||
// was a move rather than a copy.
|
||||
@ -392,7 +401,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
};
|
||||
let ty = move_place.ty(self.body, self.infcx.tcx).ty;
|
||||
let def_id = match *ty.kind() {
|
||||
ty::Adt(self_def, _) => self_def.did,
|
||||
ty::Adt(self_def, _) => self_def.did(),
|
||||
ty::Foreign(def_id)
|
||||
| ty::FnDef(def_id, _)
|
||||
| ty::Closure(def_id, _)
|
||||
@ -403,6 +412,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
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())
|
||||
&& !has_complex_bindings
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
@ -410,44 +420,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
".as_ref()".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if let Some(UseSpans::FnSelfUse {
|
||||
kind:
|
||||
CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
|
||||
..
|
||||
}) = 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(
|
||||
&infcx,
|
||||
self.param_env,
|
||||
infcx
|
||||
.tcx
|
||||
.mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)),
|
||||
def_id,
|
||||
DUMMY_SP,
|
||||
)
|
||||
}),
|
||||
_ => false,
|
||||
};
|
||||
if suggest {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
&format!("consider iterating over a slice of the `{}`'s content", ty),
|
||||
"&".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
} else if let Some(use_spans) = use_spans {
|
||||
self.explain_captures(
|
||||
&mut err, span, span, use_spans, move_place, None, "", "", "", false, true,
|
||||
);
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
fn add_move_hints(
|
||||
&self,
|
||||
error: GroupedMoveError<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
span: Span,
|
||||
) {
|
||||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
|
||||
match error {
|
||||
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
|
||||
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
@ -497,16 +478,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
|
||||
|
||||
use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
|
||||
use_spans.var_span_label(
|
||||
err,
|
||||
format!("move occurs due to use{}", use_spans.describe()),
|
||||
"moved",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_error_suggestions(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) {
|
||||
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
|
||||
let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
|
||||
for local in binds_to {
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
@ -542,7 +518,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) {
|
||||
fn add_move_error_details(&self, err: &mut Diagnostic, binds_to: &[Local]) {
|
||||
for (j, local) in binds_to.iter().enumerate() {
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
let binding_span = bind_to.source_info.span;
|
||||
|
@ -17,7 +17,7 @@ use rustc_span::{BytePos, Span};
|
||||
use crate::diagnostics::BorrowedContentSource;
|
||||
use crate::MirBorrowckCtxt;
|
||||
use rustc_const_eval::util::collect_writes::FindAssignments;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum AccessKind {
|
||||
@ -220,8 +220,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
PlaceRef {
|
||||
local,
|
||||
projection:
|
||||
[
|
||||
proj_base @ ..,
|
||||
&[
|
||||
ref proj_base @ ..,
|
||||
ProjectionElem::Deref,
|
||||
ProjectionElem::Field(field, _),
|
||||
ProjectionElem::Deref,
|
||||
@ -342,7 +342,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let tcx = self.infcx.tcx;
|
||||
if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
|
||||
if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
}
|
||||
@ -382,7 +382,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
|
||||
{
|
||||
if let ty::Closure(id, _) = ty.kind() {
|
||||
if let ty::Closure(id, _) = *ty.kind() {
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
}
|
||||
@ -687,9 +687,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
fn show_mutating_upvar(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
id: &hir::def_id::DefId,
|
||||
id: hir::def_id::DefId,
|
||||
the_place_err: PlaceRef<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
) {
|
||||
let closure_local_def_id = id.expect_local();
|
||||
let tables = tcx.typeck(closure_local_def_id);
|
||||
@ -701,7 +701,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
|
||||
let root_hir_id = upvar_id.var_path.hir_id;
|
||||
// we have an origin for this closure kind starting at this root variable so it's safe to unwrap here
|
||||
let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap();
|
||||
let captured_places = tables.closure_min_captures[&id].get(&root_hir_id).unwrap();
|
||||
|
||||
let origin_projection = closure_kind_origin
|
||||
.projections
|
||||
@ -754,7 +754,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
// Attempt to search similar mutable associated items for suggestion.
|
||||
// In the future, attempt in all path but initially for RHS of for_loop
|
||||
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic) {
|
||||
use hir::{
|
||||
BodyId, Expr,
|
||||
ExprKind::{Block, Call, DropTemps, Match, MethodCall},
|
||||
@ -787,7 +787,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
_,
|
||||
[
|
||||
Expr {
|
||||
kind: MethodCall(path_segment, ..),
|
||||
kind:
|
||||
MethodCall(
|
||||
path_segment,
|
||||
_args,
|
||||
span,
|
||||
),
|
||||
hir_id,
|
||||
..
|
||||
},
|
||||
@ -831,7 +836,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some(mut suggestions) = opt_suggestions {
|
||||
if suggestions.peek().is_some() {
|
||||
err.span_suggestions(
|
||||
path_segment.ident.span,
|
||||
*span,
|
||||
"use mutable method",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
@ -843,7 +848,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
|
||||
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
|
||||
fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &str) {
|
||||
err.span_label(sp, format!("cannot {}", act));
|
||||
|
||||
let hir = self.infcx.tcx.hir();
|
||||
@ -1083,24 +1088,20 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool {
|
||||
fn get_mut_span_in_struct_field<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
field: &mir::Field,
|
||||
field: mir::Field,
|
||||
) -> Option<Span> {
|
||||
// Expect our local to be a reference to a struct of some kind.
|
||||
if let ty::Ref(_, ty, _) = ty.kind() {
|
||||
if let ty::Adt(def, _) = ty.kind() {
|
||||
let field = def.all_fields().nth(field.index())?;
|
||||
if let ty::Ref(_, ty, _) = ty.kind()
|
||||
&& let ty::Adt(def, _) = ty.kind()
|
||||
&& let field = def.all_fields().nth(field.index())?
|
||||
// Use the HIR types to construct the diagnostic message.
|
||||
let node = tcx.hir().find_by_def_id(field.did.as_local()?)?;
|
||||
&& let node = tcx.hir().find_by_def_id(field.did.as_local()?)?
|
||||
// Now we're dealing with the actual struct that we're going to suggest a change to,
|
||||
// we can expect a field that is an immutable reference to a type.
|
||||
if let hir::Node::Field(field) = node {
|
||||
if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::Not, ty }) =
|
||||
field.ty.kind
|
||||
&& let hir::Node::Field(field) = node
|
||||
&& let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
|
||||
{
|
||||
return Some(lifetime.span.between(ty.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Some(lt.span.between(ty.span));
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! outlives constraints.
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::BTreeMap;
|
||||
@ -55,7 +55,7 @@ impl OutlivesSuggestionBuilder {
|
||||
| RegionNameSource::NamedFreeRegion(..)
|
||||
| RegionNameSource::Static => true,
|
||||
|
||||
// Don't give suggestions for upvars, closure return types, or other unnamable
|
||||
// Don't give suggestions for upvars, closure return types, or other unnameable
|
||||
// regions.
|
||||
RegionNameSource::SynthesizedFreeEnvRegion(..)
|
||||
| RegionNameSource::AnonRegionFromArgument(..)
|
||||
@ -162,7 +162,7 @@ impl OutlivesSuggestionBuilder {
|
||||
&mut self,
|
||||
mbcx: &MirBorrowckCtxt<'_, '_>,
|
||||
errci: &ErrorConstraintInfo,
|
||||
diag: &mut DiagnosticBuilder<'_>,
|
||||
diag: &mut Diagnostic,
|
||||
) {
|
||||
// Emit an intermediate note.
|
||||
let fr_name = self.region_vid_to_name(mbcx, errci.fr);
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_infer::infer::{
|
||||
error_reporting::nice_region_error::NiceRegionError,
|
||||
error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
|
||||
@ -140,15 +140,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
|
||||
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
|
||||
if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref() {
|
||||
if let ty::BoundRegionKind::BrEnv = free_region.bound_region {
|
||||
if let DefiningTy::Closure(_, substs) =
|
||||
self.regioncx.universal_regions().defining_ty
|
||||
if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref()
|
||||
&& let ty::BoundRegionKind::BrEnv = free_region.bound_region
|
||||
&& let DefiningTy::Closure(_, substs) = self.regioncx.universal_regions().defining_ty
|
||||
{
|
||||
return substs.as_closure().kind() == ty::ClosureKind::FnMut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
@ -179,7 +176,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// FIXME. We should handle this case better. It
|
||||
// indicates that we have e.g., some region variable
|
||||
// whose value is like `'a+'b` where `'a` and `'b` are
|
||||
// distinct unrelated univesal regions that are not
|
||||
// distinct unrelated universal regions that are not
|
||||
// known to outlive one another. It'd be nice to have
|
||||
// some examples where this arises to decide how best
|
||||
// to report it; we could probably handle it by
|
||||
@ -348,8 +345,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
ty::Adt(adt, substs) => {
|
||||
let generic_arg = substs[param_index as usize];
|
||||
let identity_substs =
|
||||
InternalSubsts::identity_for_item(self.infcx.tcx, adt.did);
|
||||
let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs);
|
||||
InternalSubsts::identity_for_item(self.infcx.tcx, adt.did());
|
||||
let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs);
|
||||
let base_generic_arg = identity_substs[param_index as usize];
|
||||
let adt_desc = adt.descr();
|
||||
|
||||
@ -392,7 +389,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo,
|
||||
kind: ReturnConstraint,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
|
||||
|
||||
let mut diag = self
|
||||
@ -413,7 +410,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
"returns a closure that contains a reference to a captured variable, which then \
|
||||
escapes the closure body"
|
||||
}
|
||||
ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did) => {
|
||||
ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => {
|
||||
"returns an `async` block that contains a reference to a captured variable, which then \
|
||||
escapes the closure body"
|
||||
}
|
||||
@ -469,7 +466,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// LL | ref_obj(x)
|
||||
/// | ^^^^^^^^^^ `x` escapes the function body here
|
||||
/// ```
|
||||
fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> {
|
||||
fn report_escaping_data_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let ErrorConstraintInfo { span, category, .. } = errci;
|
||||
|
||||
let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
|
||||
@ -570,7 +570,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
|
||||
/// | is returning data with lifetime `'b`
|
||||
/// ```
|
||||
fn report_general_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> {
|
||||
fn report_general_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let ErrorConstraintInfo {
|
||||
fr,
|
||||
fr_is_local,
|
||||
@ -632,7 +635,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// ```
|
||||
fn add_static_impl_trait_suggestion(
|
||||
&self,
|
||||
diag: &mut DiagnosticBuilder<'tcx>,
|
||||
diag: &mut Diagnostic,
|
||||
fr: RegionVid,
|
||||
// We need to pass `fr_name` - computing it again will label it twice.
|
||||
fr_name: RegionName,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter;
|
||||
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::ty::print::RegionHighlightMode;
|
||||
@ -98,7 +98,7 @@ impl RegionName {
|
||||
}
|
||||
}
|
||||
|
||||
crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
|
||||
crate fn highlight_region_name(&self, diag: &mut Diagnostic) {
|
||||
match &self.source {
|
||||
RegionNameSource::NamedFreeRegion(span)
|
||||
| RegionNameSource::NamedEarlyBoundRegion(span) => {
|
||||
@ -480,7 +480,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)];
|
||||
|
||||
while let Some((ty, hir_ty)) = search_stack.pop() {
|
||||
match (&ty.kind(), &hir_ty.kind) {
|
||||
match (ty.kind(), &hir_ty.kind) {
|
||||
// Check if the `ty` is `&'X ..` where `'X`
|
||||
// is the region we are looking for -- if so, and we have a `&T`
|
||||
// on the RHS, then we want to highlight the `&` like so:
|
||||
@ -532,9 +532,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
// The following cases don't have lifetimes, so we
|
||||
// just worry about trying to match up the rustc type
|
||||
// with the HIR types:
|
||||
(ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
|
||||
search_stack
|
||||
.extend(iter::zip(elem_tys.iter().map(|k| k.expect_ty()), *elem_hir_tys));
|
||||
(&ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
|
||||
search_stack.extend(iter::zip(elem_tys, *elem_hir_tys));
|
||||
}
|
||||
|
||||
(ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
|
||||
|
@ -365,7 +365,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||
// borrow); so don't check if they interfere.
|
||||
//
|
||||
// NOTE: *reservations* do conflict with themselves;
|
||||
// thus aren't injecting unsoundenss w/ this check.)
|
||||
// thus aren't injecting unsoundness w/ this check.)
|
||||
(Activation(_, activating), _) if activating == borrow_index => {
|
||||
// Activating a borrow doesn't generate any invalidations, since we
|
||||
// have already taken the reservation
|
||||
|
@ -1,15 +1,17 @@
|
||||
//! This query borrow-checks the MIR to (further) ensure it is not broken.
|
||||
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(trusted_step)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
@ -18,11 +20,11 @@ extern crate tracing;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::Node;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::ChunkedBitSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_middle::mir::{
|
||||
@ -124,8 +126,9 @@ fn mir_borrowck<'tcx>(
|
||||
) -> &'tcx BorrowCheckResult<'tcx> {
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
|
||||
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
|
||||
|
||||
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
|
||||
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let promoted: &IndexVec<_, _> = &promoted.borrow();
|
||||
do_mir_borrowck(&infcx, input_body, promoted, false).0
|
||||
@ -140,7 +143,7 @@ fn mir_borrowck<'tcx>(
|
||||
/// If `return_body_with_facts` is true, then return the body with non-erased
|
||||
/// region ids on which the borrow checking was performed together with Polonius
|
||||
/// facts.
|
||||
#[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
|
||||
#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
|
||||
fn do_mir_borrowck<'a, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
input_body: &Body<'tcx>,
|
||||
@ -153,14 +156,12 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
|
||||
let tcx = infcx.tcx;
|
||||
let param_env = tcx.param_env(def.did);
|
||||
let id = tcx.hir().local_def_id_to_hir_id(def.did);
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
||||
for var_debug_info in &input_body.var_debug_info {
|
||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||
if let Some(local) = place.as_local() {
|
||||
if let Some(prev_name) = local_names[local] {
|
||||
if var_debug_info.name != prev_name {
|
||||
if let Some(prev_name) = local_names[local] && var_debug_info.name != prev_name {
|
||||
span_bug!(
|
||||
var_debug_info.source_info.span,
|
||||
"local {:?} has many names (`{}` vs `{}`)",
|
||||
@ -169,7 +170,6 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
var_debug_info.name
|
||||
);
|
||||
}
|
||||
}
|
||||
local_names[local] = Some(var_debug_info.name);
|
||||
}
|
||||
}
|
||||
@ -179,7 +179,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
|
||||
// Gather the upvars of a closure, if any.
|
||||
let tables = tcx.typeck_opt_const_arg(def);
|
||||
if let Some(ErrorReported) = tables.tainted_by_errors {
|
||||
if let Some(ErrorGuaranteed { .. }) = tables.tainted_by_errors {
|
||||
infcx.set_tainted_by_errors();
|
||||
errors.set_tainted_by_errors();
|
||||
}
|
||||
@ -225,7 +225,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
.iterate_to_fixpoint()
|
||||
.into_results_cursor(&body);
|
||||
|
||||
let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure();
|
||||
let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def.did).is_fn_or_closure();
|
||||
let borrow_set =
|
||||
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
|
||||
|
||||
@ -288,8 +288,9 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
.pass_name("borrowck")
|
||||
.iterate_to_fixpoint();
|
||||
|
||||
let def_hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
|
||||
let movable_generator = !matches!(
|
||||
tcx.hir().get(id),
|
||||
tcx.hir().get(def_hir_id),
|
||||
Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(.., Some(hir::Movability::Static)),
|
||||
..
|
||||
@ -379,12 +380,12 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
// Convert any reservation warnings into lints.
|
||||
let reservation_warnings = mem::take(&mut mbcx.reservation_warnings);
|
||||
for (_, (place, span, location, bk, borrow)) in reservation_warnings {
|
||||
let mut initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow);
|
||||
let initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow);
|
||||
|
||||
let scope = mbcx.body.source_info(location).scope;
|
||||
let lint_root = match &mbcx.body.source_scopes[scope].local_data {
|
||||
ClearCrossCrate::Set(data) => data.lint_root,
|
||||
_ => id,
|
||||
_ => def_hir_id,
|
||||
};
|
||||
|
||||
// Span and message don't matter; we overwrite them below anyway
|
||||
@ -1047,7 +1048,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// borrow); so don't check if they interfere.
|
||||
//
|
||||
// NOTE: *reservations* do conflict with themselves;
|
||||
// thus aren't injecting unsoundenss w/ this check.)
|
||||
// thus aren't injecting unsoundness w/ this check.)
|
||||
(Activation(_, activating), _) if activating == borrow_index => {
|
||||
debug!(
|
||||
"check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
|
||||
@ -1106,7 +1107,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
// rust-lang/rust#56254 - This was previously permitted on
|
||||
// the 2018 edition so we emit it as a warning. We buffer
|
||||
// these sepately so that we only emit a warning if borrow
|
||||
// these separately so that we only emit a warning if borrow
|
||||
// checking was otherwise successful.
|
||||
this.reservation_warnings
|
||||
.insert(bi, (place_span.0, place_span.1, location, bk, borrow.clone()));
|
||||
@ -1587,7 +1588,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
) {
|
||||
debug!("check_if_reassignment_to_immutable_state({:?})", local);
|
||||
|
||||
// Check if any of the initializiations of `local` have happened yet:
|
||||
// Check if any of the initializations of `local` have happened yet:
|
||||
if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
|
||||
// And, if so, report an error.
|
||||
let init = &self.move_data.inits[init_index];
|
||||
@ -1667,7 +1668,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
location: Location,
|
||||
desired_action: InitializationRequiringAction,
|
||||
place_span: (PlaceRef<'tcx>, Span),
|
||||
maybe_uninits: &BitSet<MovePathIndex>,
|
||||
maybe_uninits: &ChunkedBitSet<MovePathIndex>,
|
||||
from: u64,
|
||||
to: u64,
|
||||
) {
|
||||
@ -1914,10 +1915,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// without going over a Deref.
|
||||
let mut shortest_uninit_seen = None;
|
||||
for prefix in this.prefixes(base, PrefixSet::Shallow) {
|
||||
let mpi = match this.move_path_for_place(prefix) {
|
||||
Some(mpi) => mpi,
|
||||
None => continue,
|
||||
};
|
||||
let Some(mpi) = this.move_path_for_place(prefix) else { continue };
|
||||
|
||||
if maybe_uninits.contains(mpi) {
|
||||
debug!(
|
||||
@ -2278,6 +2276,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
mod error {
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct BorrowckErrors<'tcx> {
|
||||
@ -2296,11 +2296,11 @@ mod error {
|
||||
/// when errors in the map are being re-added to the error buffer so that errors with the
|
||||
/// same primary span come out in a consistent order.
|
||||
buffered_move_errors:
|
||||
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
|
||||
/// Errors to be reported buffer
|
||||
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
|
||||
/// Diagnostics to be reported buffer.
|
||||
buffered: Vec<Diagnostic>,
|
||||
/// Set to Some if we emit an error during borrowck
|
||||
tainted_by_errors: Option<ErrorReported>,
|
||||
tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
impl BorrowckErrors<'_> {
|
||||
@ -2312,36 +2312,37 @@ mod error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
self.tainted_by_errors = Some(ErrorReported {});
|
||||
// FIXME(eddyb) this is a suboptimal API because `tainted_by_errors` is
|
||||
// set before any emission actually happens (weakening the guarantee).
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) {
|
||||
self.tainted_by_errors = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
|
||||
t.buffer(&mut self.buffered);
|
||||
}
|
||||
|
||||
// For diagnostics we must not set `tainted_by_errors`.
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
|
||||
t.buffer(&mut self.buffered);
|
||||
}
|
||||
|
||||
pub fn set_tainted_by_errors(&mut self) {
|
||||
self.tainted_by_errors = Some(ErrorReported {});
|
||||
self.tainted_by_errors = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) {
|
||||
self.errors.buffer_error(t);
|
||||
}
|
||||
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
|
||||
self.errors.buffer_non_error_diag(t);
|
||||
}
|
||||
|
||||
pub fn buffer_move_error(
|
||||
&mut self,
|
||||
move_out_indices: Vec<MoveOutIndex>,
|
||||
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
|
||||
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>),
|
||||
) -> bool {
|
||||
if let Some((_, mut diag)) =
|
||||
if let Some((_, diag)) =
|
||||
self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
{
|
||||
// Cancel the old diagnostic so we don't ICE
|
||||
@ -2352,7 +2353,7 @@ mod error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_errors(&mut self) -> Option<ErrorReported> {
|
||||
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
|
||||
// Buffer any move errors that we collected and de-duplicated.
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
|
||||
// We have already set tainted for this error, so just buffer it.
|
||||
@ -2362,8 +2363,8 @@ mod error {
|
||||
if !self.errors.buffered.is_empty() {
|
||||
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
|
||||
|
||||
for diag in self.errors.buffered.drain(..) {
|
||||
self.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
|
||||
for mut diag in self.errors.buffered.drain(..) {
|
||||
self.infcx.tcx.sess.diagnostic().emit_diagnostic(&mut diag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2377,7 +2378,7 @@ mod error {
|
||||
pub fn has_move_error(
|
||||
&self,
|
||||
move_out_indices: &[MoveOutIndex],
|
||||
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
|
||||
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx, ErrorGuaranteed>)> {
|
||||
self.errors.buffered_move_errors.get(move_out_indices)
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ impl LocationTable {
|
||||
}
|
||||
|
||||
impl LocationIndex {
|
||||
fn is_start(&self) -> bool {
|
||||
fn is_start(self) -> bool {
|
||||
// even indices are start points; odd indices are mid points
|
||||
(self.index() % 2) == 0
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use rustc_middle::mir::{
|
||||
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
|
||||
Promoted,
|
||||
};
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Region, RegionVid, Ty};
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid};
|
||||
use rustc_span::symbol::sym;
|
||||
use std::env;
|
||||
use std::fmt::Debug;
|
||||
@ -43,7 +43,7 @@ pub type PoloniusOutput = Output<RustcFacts>;
|
||||
/// closure requirements to propagate, and any generated errors.
|
||||
crate struct NllOutput<'tcx> {
|
||||
pub regioncx: RegionInferenceContext<'tcx>,
|
||||
pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
|
||||
pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
|
||||
pub polonius_input: Option<Box<AllFacts>>,
|
||||
pub polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
||||
@ -85,7 +85,7 @@ fn populate_polonius_move_facts(
|
||||
) {
|
||||
all_facts
|
||||
.path_is_var
|
||||
.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v)));
|
||||
.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
|
||||
|
||||
for (child, move_path) in move_data.move_paths.iter_enumerated() {
|
||||
if let Some(parent) = move_path.parent {
|
||||
@ -135,7 +135,7 @@ fn populate_polonius_move_facts(
|
||||
}
|
||||
}
|
||||
|
||||
for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() {
|
||||
for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
|
||||
if body.local_kind(local) != LocalKind::Arg {
|
||||
// Non-arguments start out deinitialised; we simulate this with an
|
||||
// initial move:
|
||||
@ -188,6 +188,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||
move_data,
|
||||
elements,
|
||||
upvars,
|
||||
use_polonius,
|
||||
);
|
||||
|
||||
if let Some(all_facts) = &mut all_facts {
|
||||
@ -225,7 +226,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||
fr1={:?}, fr2={:?}",
|
||||
fr1, fr2
|
||||
);
|
||||
all_facts.known_placeholder_subset.push((*fr1, *fr2));
|
||||
all_facts.known_placeholder_subset.push((fr1, fr2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -304,7 +305,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||
infcx.set_tainted_by_errors();
|
||||
}
|
||||
|
||||
let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span);
|
||||
let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values);
|
||||
|
||||
NllOutput {
|
||||
regioncx,
|
||||
@ -371,7 +372,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
|
||||
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
|
||||
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
|
||||
errors: &mut crate::error::BorrowckErrors<'tcx>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
|
@ -60,11 +60,9 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
|
||||
|
||||
// This Local/Local case is handled by the more general code below, but
|
||||
// it's so common that it's a speed win to check for it first.
|
||||
if let Some(l1) = borrow_place.as_local() {
|
||||
if let Some(l2) = access_place.as_local() {
|
||||
if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() {
|
||||
return l1 == l2;
|
||||
}
|
||||
}
|
||||
|
||||
place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use rustc_data_structures::binary_search_util;
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_index::vec::IndexVec;
|
||||
@ -44,6 +45,7 @@ mod reverse_sccs;
|
||||
pub mod values;
|
||||
|
||||
pub struct RegionInferenceContext<'tcx> {
|
||||
pub var_infos: VarInfos,
|
||||
/// Contains the definition for every region variable. Region
|
||||
/// variables are identified by their index (`RegionVid`). The
|
||||
/// definition contains information about where the region came
|
||||
@ -266,7 +268,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
) -> Self {
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let definitions: IndexVec<_, _> = var_infos
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
|
||||
@ -291,6 +293,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
|
||||
|
||||
let mut result = Self {
|
||||
var_infos,
|
||||
definitions,
|
||||
liveness_constraints,
|
||||
constraints,
|
||||
@ -510,7 +513,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
|
||||
/// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
|
||||
crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut rustc_errors::DiagnosticBuilder<'_>) {
|
||||
crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
|
||||
self.universal_regions.annotate(tcx, err)
|
||||
}
|
||||
|
||||
@ -786,7 +789,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let universe_a = self.scc_universes[scc_a];
|
||||
|
||||
// Quick check: if scc_b's declared universe is a subset of
|
||||
// scc_a's declared univese (typically, both are ROOT), then
|
||||
// scc_a's declared universe (typically, both are ROOT), then
|
||||
// it cannot contain any problematic universe elements.
|
||||
if universe_a.can_name(self.scc_universes[scc_b]) {
|
||||
return true;
|
||||
@ -913,9 +916,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test;
|
||||
|
||||
let generic_ty = generic_kind.to_ty(tcx);
|
||||
let subject = match self.try_promote_type_test_subject(infcx, generic_ty) {
|
||||
Some(s) => s,
|
||||
None => return false,
|
||||
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// For each region outlived by lower_bound find a non-local,
|
||||
@ -942,14 +944,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
debug!("try_promote_type_test: ur={:?}", ur);
|
||||
|
||||
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(&ur);
|
||||
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
|
||||
debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
|
||||
|
||||
// This is slightly too conservative. To show T: '1, given `'2: '1`
|
||||
// and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
|
||||
// avoid potential non-determinism we approximate this by requiring
|
||||
// T: '1 and T: '2.
|
||||
for &upper_bound in non_local_ub {
|
||||
for upper_bound in non_local_ub {
|
||||
debug_assert!(self.universal_regions.is_universal_region(upper_bound));
|
||||
debug_assert!(!self.universal_regions.is_local_free_region(upper_bound));
|
||||
|
||||
@ -1588,12 +1590,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// always will.) We'll call them `shorter_fr+` -- they're ever
|
||||
// so slightly larger than `shorter_fr`.
|
||||
let shorter_fr_plus =
|
||||
self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
|
||||
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
|
||||
debug!(
|
||||
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
|
||||
shorter_fr_plus
|
||||
);
|
||||
for &&fr in &shorter_fr_plus {
|
||||
for fr in shorter_fr_plus {
|
||||
// Push the constraint `fr-: shorter_fr+`
|
||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
subject: ClosureOutlivesSubject::Region(fr_minus),
|
||||
@ -1623,15 +1625,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// If we have some bound universal region `'a`, then the only
|
||||
// elements it can contain is itself -- we don't know anything
|
||||
// else about it!
|
||||
let error_element = match {
|
||||
let Some(error_element) = ({
|
||||
self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element {
|
||||
RegionElement::Location(_) => true,
|
||||
RegionElement::RootUniversalRegion(_) => true,
|
||||
RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
|
||||
})
|
||||
} {
|
||||
Some(v) => v,
|
||||
None => return,
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
debug!("check_bound_universal_region: error_element = {:?}", error_element);
|
||||
|
||||
@ -1992,8 +1993,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
.iter()
|
||||
.find_map(|constraint| {
|
||||
if let ConstraintCategory::Predicate(predicate_span) = constraint.category {
|
||||
// We currentl'y doesn't store the `DefId` in the `ConstraintCategory`
|
||||
// for perforamnce reasons. The error reporting code used by NLL only
|
||||
// We currently do not store the `DefId` in the `ConstraintCategory`
|
||||
// for performances reasons. The error reporting code used by NLL only
|
||||
// uses the span, so this doesn't cause any problems at the moment.
|
||||
Some(ObligationCauseCode::BindingObligation(
|
||||
CRATE_DEF_ID.to_def_id(),
|
||||
|
@ -1,10 +1,9 @@
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||
|
||||
@ -54,27 +53,40 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
pub(crate) fn infer_opaque_types(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
span: Span,
|
||||
) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
|
||||
opaque_ty_decls
|
||||
.into_iter()
|
||||
.filter_map(|(opaque_type_key, decl)| {
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
|
||||
) -> VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> {
|
||||
let mut result: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> = VecMap::new();
|
||||
for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
|
||||
let substs = opaque_type_key.substs;
|
||||
let concrete_type = decl.concrete_ty;
|
||||
debug!(?concrete_type, ?substs);
|
||||
|
||||
let mut subst_regions = vec![self.universal_regions.fr_static];
|
||||
let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
|
||||
if let ty::RePlaceholder(..) = region.kind() {
|
||||
// Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
|
||||
return region;
|
||||
}
|
||||
let vid = self.to_region_vid(region);
|
||||
trace!(?vid);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
trace!(?scc);
|
||||
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
|
||||
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
|
||||
}) {
|
||||
Some(region) => {
|
||||
let vid = self.universal_regions.to_region_vid(region);
|
||||
subst_regions.push(vid);
|
||||
self.definitions[vid].external_name.unwrap_or_else(|| {
|
||||
infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(span, "opaque type with non-universal region substs");
|
||||
region
|
||||
}
|
||||
None => {
|
||||
subst_regions.push(vid);
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
concrete_type.span,
|
||||
"opaque type with non-universal region substs",
|
||||
);
|
||||
infcx.tcx.lifetimes.re_static
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
subst_regions.sort();
|
||||
@ -97,17 +109,39 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let remapped_type = infcx.infer_opaque_definition_from_instantiation(
|
||||
opaque_type_key,
|
||||
universal_concrete_type,
|
||||
span,
|
||||
);
|
||||
|
||||
check_opaque_type_parameter_valid(
|
||||
let ty = if check_opaque_type_parameter_valid(
|
||||
infcx.tcx,
|
||||
opaque_type_key,
|
||||
OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
|
||||
)
|
||||
.then_some((opaque_type_key, remapped_type))
|
||||
})
|
||||
.collect()
|
||||
origin,
|
||||
concrete_type.span,
|
||||
) {
|
||||
remapped_type
|
||||
} else {
|
||||
infcx.tcx.ty_error()
|
||||
};
|
||||
// Sometimes two opaque types are the same only after we remap the generic parameters
|
||||
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
|
||||
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
|
||||
// once we convert the generic parameters to those of the opaque type.
|
||||
if let Some(prev) = result.get_mut(&opaque_type_key) {
|
||||
if prev.ty != ty {
|
||||
let mut err = infcx.tcx.sess.struct_span_err(
|
||||
concrete_type.span,
|
||||
&format!("hidden type `{}` differed from previous `{}`", ty, prev.ty),
|
||||
);
|
||||
err.span_note(prev.span, "previous hidden type bound here");
|
||||
err.emit();
|
||||
prev.ty = infcx.tcx.ty_error();
|
||||
}
|
||||
// Pick a better span if there is one.
|
||||
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
|
||||
prev.span = prev.span.substitute_dummy(concrete_type.span);
|
||||
} else {
|
||||
result.insert(opaque_type_key, OpaqueHiddenType { ty, span: concrete_type.span });
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Map the regions in the type to named regions. This is similar to what
|
||||
@ -149,9 +183,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
fn check_opaque_type_parameter_valid(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_type_key: OpaqueTypeKey<'_>,
|
||||
decl: OpaqueTypeDecl<'_>,
|
||||
origin: OpaqueTyOrigin,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
match decl.origin {
|
||||
match origin {
|
||||
// No need to check return position impl trait (RPIT)
|
||||
// because for type and const parameters they are correct
|
||||
// by construction: we convert
|
||||
@ -177,7 +212,6 @@ fn check_opaque_type_parameter_valid(
|
||||
// Check these
|
||||
OpaqueTyOrigin::TyAlias => {}
|
||||
}
|
||||
let span = decl.definition_span;
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
|
||||
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
|
||||
|
@ -33,12 +33,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
) -> Fallible<R>
|
||||
where
|
||||
Op: type_op::TypeOp<'tcx, Output = R>,
|
||||
Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
|
||||
Op::ErrorInfo: ToUniverseInfo<'tcx>,
|
||||
{
|
||||
let old_universe = self.infcx.universe();
|
||||
|
||||
let TypeOpOutput { output, constraints, canonicalized_query } =
|
||||
op.fully_perform(self.infcx)?;
|
||||
let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
|
||||
|
||||
if let Some(data) = &constraints {
|
||||
self.push_region_constraints(locations, category, data);
|
||||
@ -47,8 +46,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let universe = self.infcx.universe();
|
||||
|
||||
if old_universe != universe {
|
||||
let universe_info = match canonicalized_query {
|
||||
Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
|
||||
let universe_info = match error_info {
|
||||
Some(error_info) => error_info.to_universe_info(old_universe),
|
||||
None => UniverseInfo::other(),
|
||||
};
|
||||
for u in old_universe..universe {
|
||||
|
@ -99,10 +99,9 @@ impl UniversalRegionRelations<'_> {
|
||||
crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
|
||||
assert!(self.universal_regions.is_universal_region(fr1));
|
||||
assert!(self.universal_regions.is_universal_region(fr2));
|
||||
*self
|
||||
.inverse_outlives
|
||||
.postdom_upper_bound(&fr1, &fr2)
|
||||
.unwrap_or(&self.universal_regions.fr_static)
|
||||
self.inverse_outlives
|
||||
.postdom_upper_bound(fr1, fr2)
|
||||
.unwrap_or(self.universal_regions.fr_static)
|
||||
}
|
||||
|
||||
/// Finds an "upper bound" for `fr` that is not local. In other
|
||||
@ -110,7 +109,7 @@ impl UniversalRegionRelations<'_> {
|
||||
/// outlives `fr` and (b) is not local.
|
||||
///
|
||||
/// (*) If there are multiple competing choices, we return all of them.
|
||||
crate fn non_local_upper_bounds<'a>(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
|
||||
crate fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec<RegionVid> {
|
||||
debug!("non_local_upper_bound(fr={:?})", fr);
|
||||
let res = self.non_local_bounds(&self.inverse_outlives, fr);
|
||||
assert!(!res.is_empty(), "can't find an upper bound!?");
|
||||
@ -120,7 +119,7 @@ impl UniversalRegionRelations<'_> {
|
||||
/// Returns the "postdominating" bound of the set of
|
||||
/// `non_local_upper_bounds` for the given region.
|
||||
crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
|
||||
let upper_bounds = self.non_local_upper_bounds(&fr);
|
||||
let upper_bounds = self.non_local_upper_bounds(fr);
|
||||
|
||||
// In case we find more than one, reduce to one for
|
||||
// convenience. This is to prevent us from generating more
|
||||
@ -130,7 +129,7 @@ impl UniversalRegionRelations<'_> {
|
||||
debug!("non_local_bound: post_dom={:?}", post_dom);
|
||||
|
||||
post_dom
|
||||
.and_then(|&post_dom| {
|
||||
.and_then(|post_dom| {
|
||||
// If the mutual immediate postdom is not local, then
|
||||
// there is no non-local result we can return.
|
||||
if !self.universal_regions.is_local_free_region(post_dom) {
|
||||
@ -150,7 +149,7 @@ impl UniversalRegionRelations<'_> {
|
||||
/// one. See `TransitiveRelation::postdom_upper_bound` for details.
|
||||
crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
|
||||
debug!("non_local_lower_bound(fr={:?})", fr);
|
||||
let lower_bounds = self.non_local_bounds(&self.outlives, &fr);
|
||||
let lower_bounds = self.non_local_bounds(&self.outlives, fr);
|
||||
|
||||
// In case we find more than one, reduce to one for
|
||||
// convenience. This is to prevent us from generating more
|
||||
@ -159,7 +158,7 @@ impl UniversalRegionRelations<'_> {
|
||||
|
||||
debug!("non_local_bound: post_dom={:?}", post_dom);
|
||||
|
||||
post_dom.and_then(|&post_dom| {
|
||||
post_dom.and_then(|post_dom| {
|
||||
// If the mutual immediate postdom is not local, then
|
||||
// there is no non-local result we can return.
|
||||
if !self.universal_regions.is_local_free_region(post_dom) {
|
||||
@ -176,11 +175,11 @@ impl UniversalRegionRelations<'_> {
|
||||
fn non_local_bounds<'a>(
|
||||
&self,
|
||||
relation: &'a TransitiveRelation<RegionVid>,
|
||||
fr0: &'a RegionVid,
|
||||
) -> Vec<&'a RegionVid> {
|
||||
fr0: RegionVid,
|
||||
) -> Vec<RegionVid> {
|
||||
// This method assumes that `fr0` is one of the universally
|
||||
// quantified region variables.
|
||||
assert!(self.universal_regions.is_universal_region(*fr0));
|
||||
assert!(self.universal_regions.is_universal_region(fr0));
|
||||
|
||||
let mut external_parents = vec![];
|
||||
let mut queue = vec![fr0];
|
||||
@ -188,7 +187,7 @@ impl UniversalRegionRelations<'_> {
|
||||
// Keep expanding `fr` into its parents until we reach
|
||||
// non-local regions.
|
||||
while let Some(fr) = queue.pop() {
|
||||
if !self.universal_regions.is_local_free_region(*fr) {
|
||||
if !self.universal_regions.is_local_free_region(fr) {
|
||||
external_parents.push(fr);
|
||||
continue;
|
||||
}
|
||||
@ -205,17 +204,17 @@ impl UniversalRegionRelations<'_> {
|
||||
///
|
||||
/// This will only ever be true for universally quantified regions.
|
||||
crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
|
||||
self.outlives.contains(&fr1, &fr2)
|
||||
self.outlives.contains(fr1, fr2)
|
||||
}
|
||||
|
||||
/// Returns a vector of free regions `x` such that `fr1: x` is
|
||||
/// known to hold.
|
||||
crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
|
||||
self.outlives.reachable_from(&fr1)
|
||||
crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
|
||||
self.outlives.reachable_from(fr1)
|
||||
}
|
||||
|
||||
/// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
|
||||
crate fn known_outlives(&self) -> impl Iterator<Item = (&RegionVid, &RegionVid)> {
|
||||
crate fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> + '_ {
|
||||
self.outlives.base_edges()
|
||||
}
|
||||
}
|
||||
@ -254,8 +253,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
let constraint_sets: Vec<_> = unnormalized_input_output_tys
|
||||
.flat_map(|ty| {
|
||||
debug!("build: input_or_output={:?}", ty);
|
||||
// We add implied bounds from both the unnormalized and normalized ty
|
||||
// See issue #87748
|
||||
// We only add implied bounds for the normalized type as the unnormalized
|
||||
// type may not actually get checked by the caller.
|
||||
//
|
||||
// Can otherwise be unsound, see #91068.
|
||||
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
@ -268,7 +269,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
TypeOpOutput {
|
||||
output: self.infcx.tcx.ty_error(),
|
||||
constraints: None,
|
||||
canonicalized_query: None,
|
||||
error_info: None,
|
||||
}
|
||||
});
|
||||
// Note: we need this in examples like
|
||||
|
@ -147,9 +147,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
|
||||
let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
|
||||
let output_span = body.local_decls[RETURN_PLACE].source_info.span;
|
||||
if let Err(terr) = self.eq_opaque_type_and_type(
|
||||
mir_output_ty,
|
||||
if let Err(terr) = self.eq_types(
|
||||
normalized_output_ty,
|
||||
mir_output_ty,
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
@ -169,9 +169,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let user_provided_output_ty = user_provided_sig.output();
|
||||
let user_provided_output_ty =
|
||||
self.normalize(user_provided_output_ty, Locations::All(output_span));
|
||||
if let Err(err) = self.eq_opaque_type_and_type(
|
||||
mir_output_ty,
|
||||
if let Err(err) = self.eq_types(
|
||||
user_provided_output_ty,
|
||||
mir_output_ty,
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
|
@ -37,6 +37,7 @@ pub(super) fn generate<'mir, 'tcx>(
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
use_polonius: bool,
|
||||
) {
|
||||
debug!("liveness::generate");
|
||||
|
||||
@ -46,7 +47,7 @@ pub(super) fn generate<'mir, 'tcx>(
|
||||
&typeck.borrowck_context.constraints.outlives_constraints,
|
||||
);
|
||||
let live_locals = compute_live_locals(typeck.tcx(), &free_regions, &body);
|
||||
let facts_enabled = AllFacts::enabled(typeck.tcx());
|
||||
let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx());
|
||||
|
||||
let polonius_drop_used = if facts_enabled {
|
||||
let mut drop_used = Vec::new();
|
||||
|
@ -5,6 +5,7 @@ use std::{fmt, iter, mem};
|
||||
|
||||
use either::Either;
|
||||
|
||||
use hir::OpaqueTyOrigin;
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
@ -15,8 +16,8 @@ use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_infer::infer::region_constraints::RegionConstraintData;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
|
||||
@ -30,8 +31,8 @@ use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
|
||||
use rustc_middle::ty::{
|
||||
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
|
||||
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
|
||||
OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
@ -39,9 +40,11 @@ use rustc_target::abi::VariantIdx;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
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::scrape_region_constraints;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
|
||||
|
||||
use rustc_const_eval::transform::{
|
||||
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
|
||||
@ -75,7 +78,7 @@ macro_rules! span_mirbug {
|
||||
$context.last_span,
|
||||
&format!(
|
||||
"broken MIR in {:?} ({:?}): {}",
|
||||
$context.body.source.def_id(),
|
||||
$context.body().source.def_id(),
|
||||
$elem,
|
||||
format_args!($($message)*),
|
||||
),
|
||||
@ -136,6 +139,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
upvars: &[Upvar<'tcx>],
|
||||
use_polonius: bool,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
|
||||
let mut universe_causes = FxHashMap::default();
|
||||
@ -187,62 +191,55 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
&mut borrowck_context,
|
||||
|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);
|
||||
liveness::generate(
|
||||
&mut cx,
|
||||
body,
|
||||
elements,
|
||||
flow_inits,
|
||||
move_data,
|
||||
location_table,
|
||||
use_polonius,
|
||||
);
|
||||
|
||||
translate_outlives_facts(&mut cx);
|
||||
let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
|
||||
let opaque_type_values =
|
||||
infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
|
||||
opaque_type_values
|
||||
.into_iter()
|
||||
.filter_map(|(opaque_type_key, mut decl)| {
|
||||
decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
|
||||
.map(|(opaque_type_key, decl)| {
|
||||
cx.fully_perform_op(
|
||||
Locations::All(body.span),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.register_member_constraints(
|
||||
param_env,
|
||||
opaque_type_key,
|
||||
decl.hidden_type.ty,
|
||||
decl.hidden_type.span,
|
||||
);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
||||
trace!(
|
||||
"finalized opaque type {:?} to {:#?}",
|
||||
opaque_type_key,
|
||||
decl.concrete_ty.kind()
|
||||
hidden_type.ty.kind()
|
||||
);
|
||||
if decl.concrete_ty.has_infer_types_or_consts() {
|
||||
if hidden_type.has_infer_types_or_consts() {
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
body.span,
|
||||
&format!("could not resolve {:#?}", decl.concrete_ty.kind()),
|
||||
decl.hidden_type.span,
|
||||
&format!("could not resolve {:#?}", hidden_type.ty.kind()),
|
||||
);
|
||||
decl.concrete_ty = infcx.tcx.ty_error();
|
||||
hidden_type.ty = infcx.tcx.ty_error();
|
||||
}
|
||||
let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
|
||||
{
|
||||
*def_id == opaque_type_key.def_id
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if concrete_is_opaque {
|
||||
// We're using an opaque `impl Trait` type without
|
||||
// 'revealing' it. For example, code like this:
|
||||
//
|
||||
// type Foo = impl Debug;
|
||||
// fn foo1() -> Foo { ... }
|
||||
// fn foo2() -> Foo { foo1() }
|
||||
//
|
||||
// In `foo2`, we're not revealing the type of `Foo` - we're
|
||||
// just treating it as the opaque type.
|
||||
//
|
||||
// When this occurs, we do *not* want to try to equate
|
||||
// the concrete type with the underlying defining type
|
||||
// of the opaque type - this will always fail, since
|
||||
// the defining type of an opaque type is always
|
||||
// some other type (e.g. not itself)
|
||||
// Essentially, none of the normal obligations apply here -
|
||||
// we're just passing around some unknown opaque type,
|
||||
// without actually looking at the underlying type it
|
||||
// gets 'revealed' into
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: non-defining use of {:?}",
|
||||
opaque_type_key.def_id,
|
||||
);
|
||||
None
|
||||
} else {
|
||||
Some((opaque_type_key, decl))
|
||||
}
|
||||
(opaque_type_key, (hidden_type, decl.origin))
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
@ -274,7 +271,7 @@ fn type_check_internal<'a, 'tcx, R>(
|
||||
borrowck_context,
|
||||
);
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
|
||||
let mut verifier = TypeVerifier::new(&mut checker, promoted);
|
||||
verifier.visit_body(&body);
|
||||
verifier.errors_reported
|
||||
};
|
||||
@ -331,7 +328,6 @@ enum FieldAccessError {
|
||||
/// is a problem.
|
||||
struct TypeVerifier<'a, 'b, 'tcx> {
|
||||
cx: &'a mut TypeChecker<'b, 'tcx>,
|
||||
body: &'b Body<'tcx>,
|
||||
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
|
||||
last_span: Span,
|
||||
errors_reported: bool,
|
||||
@ -467,7 +463,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
self.super_rvalue(rvalue, location);
|
||||
let rval_ty = rvalue.ty(self.body, self.tcx());
|
||||
let rval_ty = rvalue.ty(self.body(), self.tcx());
|
||||
self.sanitize_type(rvalue, rval_ty);
|
||||
}
|
||||
|
||||
@ -526,10 +522,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
fn new(
|
||||
cx: &'a mut TypeChecker<'b, 'tcx>,
|
||||
body: &'b Body<'tcx>,
|
||||
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
|
||||
) -> Self {
|
||||
TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
|
||||
TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
|
||||
}
|
||||
|
||||
fn body(&self) -> &Body<'tcx> {
|
||||
self.cx.body
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
@ -554,7 +553,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
) -> PlaceTy<'tcx> {
|
||||
debug!("sanitize_place: {:?}", place);
|
||||
|
||||
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
|
||||
let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
|
||||
|
||||
for elem in place.projection.iter() {
|
||||
if place_ty.variant_index.is_none() {
|
||||
@ -599,7 +598,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
// checker on the promoted MIR, then transfer the constraints back to
|
||||
// the main MIR, changing the locations to the provided location.
|
||||
|
||||
let parent_body = mem::replace(&mut self.body, promoted_body);
|
||||
let parent_body = mem::replace(&mut self.cx.body, promoted_body);
|
||||
|
||||
// Use new sets of constraints and closure bounds so that we can
|
||||
// modify their locations.
|
||||
@ -635,7 +634,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
self.cx.typeck_mir(promoted_body);
|
||||
}
|
||||
|
||||
self.body = parent_body;
|
||||
self.cx.body = parent_body;
|
||||
// Merge the outlives constraints back in, at the given location.
|
||||
swap_constraints(self);
|
||||
|
||||
@ -697,7 +696,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
}))
|
||||
}
|
||||
ProjectionElem::Index(i) => {
|
||||
let index_ty = Place::from(i).ty(self.body, tcx).ty;
|
||||
let index_ty = Place::from(i).ty(self.body(), tcx).ty;
|
||||
if index_ty != tcx.types.usize {
|
||||
PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
|
||||
} else {
|
||||
@ -727,13 +726,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
}
|
||||
ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() {
|
||||
ty::Adt(adt_def, _substs) if adt_def.is_enum() => {
|
||||
if index.as_usize() >= adt_def.variants.len() {
|
||||
if index.as_usize() >= adt_def.variants().len() {
|
||||
PlaceTy::from_ty(span_mirbug_and_err!(
|
||||
self,
|
||||
place,
|
||||
"cast to variant #{:?} but enum only has {:?}",
|
||||
index,
|
||||
adt_def.variants.len()
|
||||
adt_def.variants().len()
|
||||
))
|
||||
} else {
|
||||
PlaceTy { ty: base_ty, variant_index: Some(index) }
|
||||
@ -807,16 +806,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
|
||||
let (variant, substs) = match base_ty {
|
||||
PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
|
||||
ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs),
|
||||
ty::Adt(adt_def, substs) => (adt_def.variant(variant_index), substs),
|
||||
ty::Generator(def_id, substs, _) => {
|
||||
let mut variants = substs.as_generator().state_tys(def_id, tcx);
|
||||
let mut variant = match variants.nth(variant_index.into()) {
|
||||
Some(v) => v,
|
||||
None => bug!(
|
||||
let Some(mut variant) = variants.nth(variant_index.into()) else {
|
||||
bug!(
|
||||
"variant_index of generator out of range: {:?}/{:?}",
|
||||
variant_index,
|
||||
substs.as_generator().state_tys(def_id, tcx).count()
|
||||
),
|
||||
);
|
||||
};
|
||||
return match variant.nth(field.index()) {
|
||||
Some(ty) => Ok(ty),
|
||||
@ -827,15 +825,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
},
|
||||
PlaceTy { ty, variant_index: None } => match *ty.kind() {
|
||||
ty::Adt(adt_def, substs) if !adt_def.is_enum() => {
|
||||
(&adt_def.variants[VariantIdx::new(0)], substs)
|
||||
(adt_def.variant(VariantIdx::new(0)), substs)
|
||||
}
|
||||
ty::Closure(_, substs) => {
|
||||
return match substs
|
||||
.as_closure()
|
||||
.tupled_upvars_ty()
|
||||
.tuple_element_ty(field.index())
|
||||
.tuple_fields()
|
||||
.get(field.index())
|
||||
{
|
||||
Some(ty) => Ok(ty),
|
||||
Some(&ty) => Ok(ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
field_count: substs.as_closure().upvar_tys().count(),
|
||||
}),
|
||||
@ -853,7 +852,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
}
|
||||
ty::Tuple(tys) => {
|
||||
return match tys.get(field.index()) {
|
||||
Some(&ty) => Ok(ty.expect_ty()),
|
||||
Some(&ty) => Ok(ty),
|
||||
None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }),
|
||||
};
|
||||
}
|
||||
@ -906,7 +905,7 @@ struct BorrowCheckContext<'a, 'tcx> {
|
||||
crate struct MirTypeckResults<'tcx> {
|
||||
crate constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
|
||||
}
|
||||
|
||||
/// A collection of region constraints that must be satisfied for the
|
||||
@ -1056,17 +1055,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
checker
|
||||
}
|
||||
|
||||
fn body(&self) -> &Body<'tcx> {
|
||||
self.body
|
||||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
let features = self.tcx().features();
|
||||
features.unsized_locals || features.unsized_fn_params
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
debug!(
|
||||
"check_user_type_annotations: user_type_annotations={:?}",
|
||||
self.user_type_annotations
|
||||
);
|
||||
debug!(?self.user_type_annotations);
|
||||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
|
||||
@ -1189,7 +1190,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
tcx,
|
||||
self.param_env,
|
||||
proj,
|
||||
|this, field, &()| {
|
||||
|this, field, ()| {
|
||||
let ty = this.field_ty(tcx, field);
|
||||
self.normalize(ty, locations)
|
||||
},
|
||||
@ -1207,131 +1208,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Equates a type `anon_ty` that may contain opaque types whose
|
||||
/// values are to be inferred by the MIR.
|
||||
///
|
||||
/// The type `revealed_ty` contains the same type as `anon_ty`, but with the
|
||||
/// hidden types for impl traits revealed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Consider a piece of code like
|
||||
///
|
||||
/// ```rust
|
||||
/// type Foo<U> = impl Debug;
|
||||
///
|
||||
/// fn foo<T: Debug>(t: T) -> Box<Foo<T>> {
|
||||
/// Box::new((t, 22_u32))
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here, the function signature would be something like
|
||||
/// `fn(T) -> Box<impl Debug>`. The MIR return slot would have
|
||||
/// the type with the opaque type revealed, so `Box<(T, u32)>`.
|
||||
///
|
||||
/// In terms of our function parameters:
|
||||
///
|
||||
/// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type
|
||||
/// scoped to this function (note that it is parameterized by the
|
||||
/// generics of `foo`). Note that `anon_ty` is not just the opaque type,
|
||||
/// but the entire return type (which may contain opaque types within it).
|
||||
/// * `revealed_ty` would be `Box<(T, u32)>`
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn eq_opaque_type_and_type(
|
||||
&mut self,
|
||||
revealed_ty: Ty<'tcx>,
|
||||
anon_ty: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
// Fast path for the common case.
|
||||
if !anon_ty.has_opaque_types() {
|
||||
if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
locations,
|
||||
"eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
|
||||
revealed_ty,
|
||||
anon_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let param_env = self.param_env;
|
||||
let body = self.body;
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
|
||||
debug!(?mir_def_id);
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
|
||||
let dummy_body_id = hir::CRATE_HIR_ID;
|
||||
|
||||
// Replace the opaque types defined by this function with
|
||||
// inference variables, creating a map. In our example above,
|
||||
// this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type)
|
||||
// to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
|
||||
// (Note that the key of the map is both the def-id of `Foo` along with
|
||||
// any generic parameters.)
|
||||
let output_ty = obligations.add(infcx.instantiate_opaque_types(
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
anon_ty,
|
||||
locations.span(body),
|
||||
));
|
||||
debug!(?output_ty, ?revealed_ty);
|
||||
|
||||
// Make sure that the inferred types are well-formed. I'm
|
||||
// not entirely sure this is needed (the HIR type check
|
||||
// didn't do this) but it seems sensible to prevent opaque
|
||||
// types hiding ill-formed types.
|
||||
obligations.obligations.push(traits::Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
|
||||
.to_predicate(infcx.tcx),
|
||||
));
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?,
|
||||
);
|
||||
|
||||
debug!("equated");
|
||||
|
||||
Ok(InferOk { value: (), obligations: obligations.into_vec() })
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
// 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
|
||||
// instantiated it with).
|
||||
let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
|
||||
for (opaque_type_key, opaque_decl) in opaque_type_map {
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
@ -1440,7 +1316,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
};
|
||||
if variant_index.as_usize() >= adt.variants.len() {
|
||||
if variant_index.as_usize() >= adt.variants().len() {
|
||||
span_bug!(
|
||||
stmt.source_info.span,
|
||||
"bad set discriminant ({:?} = {:?}): value of of range",
|
||||
@ -1919,7 +1795,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
match *ak {
|
||||
AggregateKind::Adt(adt_did, variant_index, substs, _, active_field_index) => {
|
||||
let def = tcx.adt_def(adt_did);
|
||||
let variant = &def.variants[variant_index];
|
||||
let variant = &def.variant(variant_index);
|
||||
let adj_field_index = active_field_index.unwrap_or(field_index);
|
||||
if let Some(field) = variant.fields.get(adj_field_index) {
|
||||
Ok(self.normalize(field.ty(tcx, substs), location))
|
||||
@ -2023,7 +1899,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
ObligationCause::new(
|
||||
span,
|
||||
self.tcx().hir().local_def_id_to_hir_id(def_id),
|
||||
traits::ObligationCauseCode::RepeatVec(is_const_fn),
|
||||
traits::ObligationCauseCode::RepeatElementCopy {
|
||||
is_const_fn,
|
||||
},
|
||||
),
|
||||
self.param_env,
|
||||
ty::Binder::dummy(ty::TraitRef::new(
|
||||
@ -2178,12 +2056,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
|
||||
CastKind::Pointer(PointerCast::MutToConstPointer) => {
|
||||
let ty_from = match op.ty(body, tcx).kind() {
|
||||
ty::RawPtr(ty::TypeAndMut {
|
||||
let ty::RawPtr(ty::TypeAndMut {
|
||||
ty: ty_from,
|
||||
mutbl: hir::Mutability::Mut,
|
||||
}) => ty_from,
|
||||
_ => {
|
||||
}) = op.ty(body, tcx).kind() else {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
@ -2191,14 +2067,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
ty,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let ty_to = match ty.kind() {
|
||||
ty::RawPtr(ty::TypeAndMut {
|
||||
let ty::RawPtr(ty::TypeAndMut {
|
||||
ty: ty_to,
|
||||
mutbl: hir::Mutability::Not,
|
||||
}) => ty_to,
|
||||
_ => {
|
||||
}) = ty.kind() else {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
@ -2206,7 +2079,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
ty,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Err(terr) = self.sub_types(
|
||||
*ty_from,
|
||||
@ -2238,9 +2110,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let (ty_elem, ty_mut) = match opt_ty_elem_mut {
|
||||
Some(ty_elem_mut) => ty_elem_mut,
|
||||
None => {
|
||||
let Some((ty_elem, ty_mut)) = opt_ty_elem_mut else {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
@ -2248,7 +2118,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
ty_from,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let (ty_to, ty_to_mut) = match ty.kind() {
|
||||
@ -2640,7 +2509,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// we have to solve them here where we instantiate the
|
||||
// closure.
|
||||
//
|
||||
// Despite the opacity of the previous parapgrah, this is
|
||||
// Despite the opacity of the previous paragraph, this is
|
||||
// actually relatively easy to understand in terms of the
|
||||
// desugaring. A closure gets desugared to a struct, and
|
||||
// these extra requirements are basically like where
|
||||
@ -2772,19 +2641,31 @@ impl NormalizeLocation for Location {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ObligationAccumulator<'tcx> {
|
||||
obligations: PredicateObligations<'tcx>,
|
||||
/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s,
|
||||
/// this is not canonicalized - it directly affects the main `InferCtxt`
|
||||
/// that we use during MIR borrowchecking.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct InstantiateOpaqueType<'tcx> {
|
||||
pub base_universe: Option<ty::UniverseIndex>,
|
||||
pub region_constraints: Option<RegionConstraintData<'tcx>>,
|
||||
pub obligations: Vec<PredicateObligation<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationAccumulator<'tcx> {
|
||||
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
|
||||
let InferOk { value, obligations } = value;
|
||||
self.obligations.extend(obligations);
|
||||
value
|
||||
}
|
||||
impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
|
||||
type Output = ();
|
||||
/// We use this type itself to store the information used
|
||||
/// when reporting errors. Since this is not a query, we don't
|
||||
/// re-run anything during error reporting - we just use the information
|
||||
/// we saved to help extract an error from the already-existing region
|
||||
/// constraints in our `InferCtxt`
|
||||
type ErrorInfo = InstantiateOpaqueType<'tcx>;
|
||||
|
||||
fn into_vec(self) -> PredicateObligations<'tcx> {
|
||||
self.obligations
|
||||
fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
|
||||
let (mut output, region_constraints) = scrape_region_constraints(infcx, || {
|
||||
Ok(InferOk { value: (), obligations: self.obligations.clone() })
|
||||
})?;
|
||||
self.region_constraints = Some(region_constraints);
|
||||
output.error_info = Some(self);
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::type_check::{Locations, TypeChecker};
|
||||
use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};
|
||||
|
||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
|
||||
@ -63,6 +66,10 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.locations.span(self.type_checker.body)
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.type_checker.param_env
|
||||
}
|
||||
@ -117,6 +124,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
|
||||
// We don't have to worry about the equality of consts during borrow checking
|
||||
// as consts always have a static lifetime.
|
||||
// FIXME(oli-obk): is this really true? We can at least have HKL and with
|
||||
// inline consts we may have further lifetimes that may be unsound to treat as
|
||||
// 'static.
|
||||
fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
@ -126,4 +136,34 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn register_opaque_type(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
let param_env = self.param_env();
|
||||
let span = self.span();
|
||||
let def_id = self.type_checker.body.source.def_id().expect_local();
|
||||
let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
self.type_checker
|
||||
.fully_perform_op(
|
||||
self.locations,
|
||||
self.category,
|
||||
InstantiateOpaqueType {
|
||||
obligations: self
|
||||
.type_checker
|
||||
.infcx
|
||||
.handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
|
||||
.obligations,
|
||||
// These fields are filled in during execution of the operation
|
||||
base_universe: None,
|
||||
region_constraints: None,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
use either::Either;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
@ -336,7 +336,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
/// that this region imposes on others. The methods in this file
|
||||
/// handle the part about dumping the inference context internal
|
||||
/// state.
|
||||
crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) {
|
||||
crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
|
||||
match self.defining_ty {
|
||||
DefiningTy::Closure(def_id, substs) => {
|
||||
err.note(&format!(
|
||||
@ -524,7 +524,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
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) {
|
||||
match tcx.hir().body_owner_kind(self.mir_def.did) {
|
||||
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
|
||||
let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
tcx.type_of(typeck_root_def_id)
|
||||
@ -641,16 +641,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let (&output, tuplized_inputs) =
|
||||
inputs_and_output.skip_binder().split_last().unwrap();
|
||||
assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs");
|
||||
let inputs = match tuplized_inputs[0].kind() {
|
||||
ty::Tuple(inputs) => inputs,
|
||||
_ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]),
|
||||
let &ty::Tuple(inputs) = tuplized_inputs[0].kind() else {
|
||||
bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]);
|
||||
};
|
||||
|
||||
ty::Binder::bind_with_vars(
|
||||
tcx.mk_type_list(
|
||||
iter::once(closure_ty)
|
||||
.chain(inputs.iter().map(|k| k.expect_ty()))
|
||||
.chain(iter::once(output)),
|
||||
iter::once(closure_ty).chain(inputs).chain(iter::once(output)),
|
||||
),
|
||||
bound_vars,
|
||||
)
|
||||
@ -728,6 +725,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, indices))]
|
||||
fn replace_bound_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
origin: NllRegionVariableOrigin,
|
||||
@ -738,22 +736,15 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
debug!(
|
||||
"replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
|
||||
value, all_outlive_scope,
|
||||
);
|
||||
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
|
||||
debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
|
||||
debug!(?br);
|
||||
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
|
||||
scope: all_outlive_scope.to_def_id(),
|
||||
bound_region: br.kind,
|
||||
}));
|
||||
let region_vid = self.next_nll_region_var(origin);
|
||||
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
|
||||
debug!(
|
||||
"replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
|
||||
liberated_region, region_vid
|
||||
);
|
||||
debug!(?liberated_region, ?region_vid);
|
||||
region_vid
|
||||
});
|
||||
value
|
||||
@ -768,6 +759,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
/// entries for them and store them in the indices map. This code iterates over the complete
|
||||
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
|
||||
/// inputs vector.
|
||||
#[instrument(skip(self, indices))]
|
||||
fn replace_late_bound_regions_with_nll_infer_vars(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
@ -779,6 +771,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
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);
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
}
|
||||
});
|
||||
|
@ -3,7 +3,7 @@ use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_parse_format as parse;
|
||||
@ -30,7 +30,7 @@ fn parse_args<'a>(
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
is_global_asm: bool,
|
||||
) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
|
||||
) -> PResult<'a, AsmArgs> {
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
let sess = &ecx.sess.parse_sess;
|
||||
parse_asm_args(&mut p, sess, sp, is_global_asm)
|
||||
@ -43,7 +43,7 @@ pub fn parse_asm_args<'a>(
|
||||
sess: &'a ParseSess,
|
||||
sp: Span,
|
||||
is_global_asm: bool,
|
||||
) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
|
||||
) -> PResult<'a, AsmArgs> {
|
||||
let diag = &sess.span_diagnostic;
|
||||
|
||||
if p.token == token::Eof {
|
||||
@ -390,7 +390,7 @@ fn parse_options<'a>(
|
||||
p: &mut Parser<'a>,
|
||||
args: &mut AsmArgs,
|
||||
is_global_asm: bool,
|
||||
) -> Result<(), DiagnosticBuilder<'a>> {
|
||||
) -> PResult<'a, ()> {
|
||||
let span_start = p.prev_token.span;
|
||||
|
||||
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
|
||||
@ -431,10 +431,7 @@ fn parse_options<'a>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_clobber_abi<'a>(
|
||||
p: &mut Parser<'a>,
|
||||
args: &mut AsmArgs,
|
||||
) -> Result<(), DiagnosticBuilder<'a>> {
|
||||
fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, ()> {
|
||||
let span_start = p.prev_token.span;
|
||||
|
||||
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
|
||||
@ -501,7 +498,7 @@ fn parse_clobber_abi<'a>(
|
||||
fn parse_reg<'a>(
|
||||
p: &mut Parser<'a>,
|
||||
explicit_reg: &mut bool,
|
||||
) -> Result<ast::InlineAsmRegOrRegClass, DiagnosticBuilder<'a>> {
|
||||
) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
|
||||
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
|
||||
let result = match p.token.uninterpolate().kind {
|
||||
token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name),
|
||||
|
@ -4,7 +4,7 @@ use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_expand::base::*;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
@ -83,11 +83,7 @@ struct Assert {
|
||||
custom_message: Option<TokenStream>,
|
||||
}
|
||||
|
||||
fn parse_assert<'a>(
|
||||
cx: &mut ExtCtxt<'a>,
|
||||
sp: Span,
|
||||
stream: TokenStream,
|
||||
) -> Result<Assert, DiagnosticBuilder<'a>> {
|
||||
fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
|
||||
let mut parser = cx.new_parser_from_tts(stream);
|
||||
|
||||
if parser.token == token::Eof {
|
||||
|
@ -6,7 +6,7 @@ use rustc_ast as ast;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_attr as attr;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_span::Span;
|
||||
|
||||
@ -19,7 +19,12 @@ pub fn expand_cfg(
|
||||
|
||||
match parse_cfg(cx, sp, tts) {
|
||||
Ok(cfg) => {
|
||||
let matches_cfg = attr::cfg_matches(&cfg, &cx.sess.parse_sess, cx.ecfg.features);
|
||||
let matches_cfg = attr::cfg_matches(
|
||||
&cfg,
|
||||
&cx.sess.parse_sess,
|
||||
cx.current_expansion.lint_node_id,
|
||||
cx.ecfg.features,
|
||||
);
|
||||
MacEager::expr(cx.expr_bool(sp, matches_cfg))
|
||||
}
|
||||
Err(mut err) => {
|
||||
@ -29,11 +34,7 @@ pub fn expand_cfg(
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_cfg<'a>(
|
||||
cx: &mut ExtCtxt<'a>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Result<ast::MetaItem, DiagnosticBuilder<'a>> {
|
||||
fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
|
@ -44,9 +44,8 @@ impl MultiItemModifier for Expander {
|
||||
template,
|
||||
);
|
||||
|
||||
let path = match validate_input(ecx, meta_item) {
|
||||
Some(path) => path,
|
||||
None => return ExpandResult::Ready(Vec::new()),
|
||||
let Some(path) = validate_input(ecx, meta_item) else {
|
||||
return ExpandResult::Ready(Vec::new());
|
||||
};
|
||||
|
||||
match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) {
|
||||
|
@ -5,6 +5,7 @@ use rustc_ast::mut_visit::MutVisitor;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast::{mut_visit, visit};
|
||||
use rustc_ast::{AstLike, Attribute};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
@ -26,15 +27,16 @@ crate fn expand(
|
||||
) -> Vec<Annotatable> {
|
||||
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
|
||||
warn_on_duplicate_attribute(&ecx, &annotatable, sym::cfg_eval);
|
||||
vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
|
||||
vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable, ecx.current_expansion.lint_node_id)]
|
||||
}
|
||||
|
||||
crate fn cfg_eval(
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
annotatable: Annotatable,
|
||||
lint_node_id: NodeId,
|
||||
) -> Annotatable {
|
||||
CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
|
||||
CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } }
|
||||
.configure_annotatable(annotatable)
|
||||
// Since the item itself has already been configured by the `InvocationCollector`,
|
||||
// we know that fold result vector will contain exactly one element.
|
||||
@ -135,7 +137,7 @@ impl CfgEval<'_, '_> {
|
||||
}
|
||||
|
||||
// The majority of parsed attribute targets will never need to have early cfg-expansion
|
||||
// run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro inoput).
|
||||
// run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro input).
|
||||
// Therefore, we normally do not capture the necessary information about `#[cfg]`
|
||||
// and `#[cfg_attr]` attributes during parsing.
|
||||
//
|
||||
@ -201,7 +203,7 @@ impl CfgEval<'_, '_> {
|
||||
|
||||
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
||||
// to the captured `AttrAnnotatedTokenStream` (specifically, we capture
|
||||
// `AttrAnnotatedTokenTree::AttributesData` for all occurences of `#[cfg]` and `#[cfg_attr]`)
|
||||
// `AttrAnnotatedTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
|
||||
let mut parser =
|
||||
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
|
||||
parser.capture_cfg = true;
|
||||
|
@ -9,9 +9,8 @@ pub fn expand_compile_error<'cx>(
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") {
|
||||
None => return DummyResult::any(sp),
|
||||
Some(v) => v,
|
||||
let Some(var) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
|
||||
cx.span_err(sp, &var);
|
||||
|
@ -10,9 +10,8 @@ pub fn expand_concat(
|
||||
sp: rustc_span::Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'static> {
|
||||
let es = match base::get_exprs_from_tts(cx, sp, tts) {
|
||||
Some(e) => e,
|
||||
None => return DummyResult::any(sp),
|
||||
let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let mut accumulator = String::new();
|
||||
let mut missing_literal = vec![];
|
||||
|
@ -121,9 +121,8 @@ pub fn expand_concat_bytes(
|
||||
sp: rustc_span::Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'static> {
|
||||
let es = match base::get_exprs_from_tts(cx, sp, tts) {
|
||||
Some(e) => e,
|
||||
None => return DummyResult::any(sp),
|
||||
let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let mut accumulator = Vec::new();
|
||||
let mut missing_literals = vec![];
|
||||
|
@ -64,7 +64,12 @@ impl MultiItemModifier for Expander {
|
||||
match &mut resolutions[..] {
|
||||
[] => {}
|
||||
[(_, first_item, _), others @ ..] => {
|
||||
*first_item = cfg_eval(sess, features, item.clone());
|
||||
*first_item = cfg_eval(
|
||||
sess,
|
||||
features,
|
||||
item.clone(),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
);
|
||||
for (_, item, _) in others {
|
||||
*item = first_item.clone();
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub fn expand_deriving_clone(
|
||||
// - the item is a union with Copy fields
|
||||
// Unions with generic parameters still can derive Clone because they require Copy
|
||||
// for deriving, Clone alone is not enough.
|
||||
// Whever Clone is implemented for fields is irrelevant so we don't assert it.
|
||||
// Wherever Clone is implemented for fields is irrelevant so we don't assert it.
|
||||
let bounds;
|
||||
let substructure;
|
||||
let is_shallow;
|
||||
@ -196,12 +196,11 @@ fn cs_clone(
|
||||
let fields = all_fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let ident = match field.name {
|
||||
Some(i) => i,
|
||||
None => cx.span_bug(
|
||||
let Some(ident) = field.name else {
|
||||
cx.span_bug(
|
||||
trait_span,
|
||||
&format!("unnamed field in normal struct in `derive({})`", name,),
|
||||
),
|
||||
);
|
||||
};
|
||||
let call = subcall(cx, field);
|
||||
cx.field_imm(field.span, ident, call)
|
||||
|
@ -83,9 +83,8 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
|
||||
// }
|
||||
|
||||
let new = {
|
||||
let other_f = match other_fs {
|
||||
[o_f] => o_f,
|
||||
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"),
|
||||
let [other_f] = other_fs else {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
};
|
||||
|
||||
let args =
|
||||
|
@ -26,9 +26,8 @@ pub fn expand_deriving_partial_eq(
|
||||
base: bool,
|
||||
) -> P<Expr> {
|
||||
let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
|
||||
let other_f = match other_fs {
|
||||
[o_f] => o_f,
|
||||
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"),
|
||||
let [other_f] = other_fs else {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`");
|
||||
};
|
||||
|
||||
cx.expr_binary(span, op, self_f, other_f.clone())
|
||||
|
@ -86,9 +86,8 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
||||
// }
|
||||
|
||||
let new = {
|
||||
let other_f = match other_fs {
|
||||
[o_f] => o_f,
|
||||
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
|
||||
let [other_f] = other_fs else {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`");
|
||||
};
|
||||
|
||||
let args =
|
||||
|
@ -101,9 +101,8 @@ fn default_enum_substructure(
|
||||
trait_span: Span,
|
||||
enum_def: &EnumDef,
|
||||
) -> P<Expr> {
|
||||
let default_variant = match extract_default_variant(cx, enum_def, trait_span) {
|
||||
Ok(value) => value,
|
||||
Err(()) => return DummyResult::raw_expr(trait_span, true),
|
||||
let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) else {
|
||||
return DummyResult::raw_expr(trait_span, true);
|
||||
};
|
||||
|
||||
// At this point, we know that there is exactly one variant with a `#[default]` attribute. The
|
||||
|
@ -560,6 +560,11 @@ impl<'a> TraitDef<'a> {
|
||||
kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
generics: Generics::default(),
|
||||
where_clauses: (
|
||||
ast::TyAliasWhereClause::default(),
|
||||
ast::TyAliasWhereClause::default(),
|
||||
),
|
||||
where_predicates_split: 0,
|
||||
bounds: Vec::new(),
|
||||
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
|
||||
})),
|
||||
|
@ -48,9 +48,8 @@ pub fn expand_deriving_hash(
|
||||
}
|
||||
|
||||
fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
||||
let state_expr = match substr.nonself_args {
|
||||
[o_f] => o_f,
|
||||
_ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"),
|
||||
let [state_expr] = substr.nonself_args else {
|
||||
cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
|
||||
};
|
||||
let call_hash = |span, thing_expr| {
|
||||
let hash_path = {
|
||||
|
@ -116,9 +116,8 @@ fn inject_impl_of_structural_trait(
|
||||
structural_path: generic::ty::Path,
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
) {
|
||||
let item = match *item {
|
||||
Annotatable::Item(ref item) => item,
|
||||
_ => unreachable!(),
|
||||
let Annotatable::Item(ref item) = *item else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let generics = match item.kind {
|
||||
|
@ -70,7 +70,7 @@ fn expand<'cx>(
|
||||
}
|
||||
|
||||
pub fn use_panic_2021(mut span: Span) -> bool {
|
||||
// To determine the editon, we check the first span up the expansion
|
||||
// To determine the edition, we check the first span up the expansion
|
||||
// stack that does not have #[allow_internal_unstable(edition_panic)].
|
||||
// (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
|
||||
loop {
|
||||
|
@ -16,9 +16,8 @@ pub fn expand_option_env<'cx>(
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
|
||||
None => return DummyResult::any(sp),
|
||||
Some(v) => v,
|
||||
let Some(var) = get_single_str_from_tts(cx, sp, tts, "option_env!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
@ -62,9 +61,8 @@ pub fn expand_env<'cx>(
|
||||
Some(exprs) => exprs.into_iter(),
|
||||
};
|
||||
|
||||
let var = match expr_to_string(cx, exprs.next().unwrap(), "expected string literal") {
|
||||
None => return DummyResult::any(sp),
|
||||
Some((v, _style)) => v,
|
||||
let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let msg = match exprs.next() {
|
||||
None => Symbol::intern(&format!("environment variable `{}` not defined", var)),
|
||||
|
@ -7,7 +7,7 @@ use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{token, BlockCheckMode, UnsafeSource};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{pluralize, Applicability, PResult};
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_parse_format as parse;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
@ -130,7 +130,7 @@ fn parse_args<'a>(
|
||||
ecx: &mut ExtCtxt<'a>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>), DiagnosticBuilder<'a>> {
|
||||
) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>)> {
|
||||
let mut args = Vec::<P<ast::Expr>>::new();
|
||||
let mut names = FxHashMap::<Symbol, usize>::default();
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![recursion_limit = "256"]
|
||||
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
|
@ -103,10 +103,8 @@ impl<'a> CollectProcMacros<'a> {
|
||||
}
|
||||
|
||||
fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
|
||||
let (trait_name, proc_attrs) =
|
||||
match parse_macro_name_and_helper_attrs(self.handler, attr, "derive") {
|
||||
Some(name_and_attrs) => name_and_attrs,
|
||||
None => return,
|
||||
let Some((trait_name, proc_attrs)) = parse_macro_name_and_helper_attrs(self.handler, attr, "derive") else {
|
||||
return;
|
||||
};
|
||||
|
||||
if self.in_root && item.vis.kind.is_pub() {
|
||||
@ -219,15 +217,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let attr = match found_attr {
|
||||
None => {
|
||||
let Some(attr) = found_attr else {
|
||||
self.check_not_pub_in_root(&item.vis, self.source_map.guess_head_span(item.span));
|
||||
let prev_in_root = mem::replace(&mut self.in_root, false);
|
||||
visit::walk_item(self, item);
|
||||
self.in_root = prev_in_root;
|
||||
return;
|
||||
}
|
||||
Some(attr) => attr,
|
||||
};
|
||||
|
||||
if !is_fn {
|
||||
|
@ -3,15 +3,17 @@ use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::{self, new_parser_from_file};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{self, Pos, Span};
|
||||
use rustc_span::{self, FileName, Pos, Span};
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
// These macros all relate to the file system; they either return
|
||||
@ -98,12 +100,11 @@ pub fn expand_include<'cx>(
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
|
||||
Some(f) => f,
|
||||
None => return DummyResult::any(sp),
|
||||
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
// The file will be added to the code map by the parser
|
||||
let file = match cx.resolve_path(file, sp) {
|
||||
let file = match resolve_path(cx, file, sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
@ -169,11 +170,10 @@ pub fn expand_include_str(
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'static> {
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
|
||||
Some(f) => f,
|
||||
None => return DummyResult::any(sp),
|
||||
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let file = match cx.resolve_path(file, sp) {
|
||||
let file = match resolve_path(cx, file, sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
@ -204,11 +204,10 @@ pub fn expand_include_bytes(
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'static> {
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
|
||||
Some(f) => f,
|
||||
None => return DummyResult::any(sp),
|
||||
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let file = match cx.resolve_path(file, sp) {
|
||||
let file = match resolve_path(cx, file, sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
@ -223,3 +222,40 @@ pub fn expand_include_bytes(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a `path` mentioned inside Rust code, returning an absolute path.
|
||||
///
|
||||
/// This unifies the logic used for resolving `include_X!`.
|
||||
fn resolve_path<'a>(
|
||||
cx: &mut ExtCtxt<'a>,
|
||||
path: impl Into<PathBuf>,
|
||||
span: Span,
|
||||
) -> PResult<'a, PathBuf> {
|
||||
let path = path.into();
|
||||
|
||||
// Relative paths are resolved relative to the file in which they are found
|
||||
// after macro expansion (that is, they are unhygienic).
|
||||
if !path.is_absolute() {
|
||||
let callsite = span.source_callsite();
|
||||
let mut result = match cx.source_map().span_to_filename(callsite) {
|
||||
FileName::Real(name) => name
|
||||
.into_local_path()
|
||||
.expect("attempting to resolve a file path in an external file"),
|
||||
FileName::DocTest(path, _) => path,
|
||||
other => {
|
||||
return Err(cx.struct_span_err(
|
||||
span,
|
||||
&format!(
|
||||
"cannot resolve relative path in non-file source `{}`",
|
||||
cx.source_map().filename_for_diagnostics(&other)
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
result.pop();
|
||||
result.push(path);
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,10 @@ pub fn expand_test_or_bench(
|
||||
// These were a warning before #92959 and need to continue being that to avoid breaking
|
||||
// stable user code (#94508).
|
||||
ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg),
|
||||
_ => diag.struct_span_err(attr_sp, msg),
|
||||
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
|
||||
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
|
||||
// reworked in the future to not need it, it'd be nice.
|
||||
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
|
||||
};
|
||||
err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
|
||||
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
|
||||
@ -263,6 +266,15 @@ pub fn expand_test_or_bench(
|
||||
"ignore",
|
||||
cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
|
||||
),
|
||||
// ignore_message: Some("...") | None
|
||||
field(
|
||||
"ignore_message",
|
||||
if let Some(msg) = should_ignore_message(cx, &item) {
|
||||
cx.expr_some(sp, cx.expr_str(sp, msg))
|
||||
} else {
|
||||
cx.expr_none(sp)
|
||||
},
|
||||
),
|
||||
// compile_fail: true | false
|
||||
field("compile_fail", cx.expr_bool(sp, false)),
|
||||
// no_run: true | false
|
||||
@ -365,6 +377,20 @@ fn should_ignore(sess: &Session, i: &ast::Item) -> bool {
|
||||
sess.contains_name(&i.attrs, sym::ignore)
|
||||
}
|
||||
|
||||
fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> {
|
||||
match cx.sess.find_by_name(&i.attrs, sym::ignore) {
|
||||
Some(attr) => {
|
||||
match attr.meta_item_list() {
|
||||
// Handle #[ignore(bar = "foo")]
|
||||
Some(_) => None,
|
||||
// Handle #[ignore] and #[ignore = "message"]
|
||||
None => attr.value_str(),
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
|
||||
match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
|
||||
Some(attr) => {
|
||||
|
@ -112,7 +112,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||
fn visit_crate(&mut self, c: &mut ast::Crate) {
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
noop_visit_crate(c, self);
|
||||
self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests);
|
||||
self.add_test_cases(ast::CRATE_NODE_ID, c.spans.inner_span, prev_tests);
|
||||
|
||||
// Create a main function to run our tests
|
||||
c.items.push(mk_main(&mut self.cx));
|
||||
@ -129,7 +129,8 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||
|
||||
// We don't want to recurse into anything other than mods, since
|
||||
// mods or tests inside of functions will break things
|
||||
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind {
|
||||
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ref spans)) = item.kind {
|
||||
let ast::ModSpans { inner_span: span, inject_use_span: _ } = *spans;
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
noop_visit_item_kind(&mut item.kind, self);
|
||||
self.add_test_cases(item.id, span, prev_tests);
|
||||
@ -376,9 +377,13 @@ fn get_test_runner(
|
||||
match &*meta_list {
|
||||
[single] => match single.meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
|
||||
_ => sd.struct_span_err(span, "`test_runner` argument must be a path").emit(),
|
||||
_ => {
|
||||
sd.struct_span_err(span, "`test_runner` argument must be a path").emit();
|
||||
}
|
||||
},
|
||||
_ => sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit(),
|
||||
_ => {
|
||||
sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
84
compiler/rustc_codegen_cranelift/Cargo.lock
generated
84
compiler/rustc_codegen_cranelift/Cargo.lock
generated
@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.51"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
|
||||
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
|
||||
|
||||
[[package]]
|
||||
name = "ar"
|
||||
@ -15,9 +15,9 @@ source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@ -33,18 +33,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc0cb7df82c8cf8f2e6a8dd394a0932a71369c160cc9b027dca414fced242513"
|
||||
checksum = "d16922317bd7dd104d509a373887822caa0242fc1def00de66abb538db221db4"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe4463c15fa42eee909e61e5eac4866b7c6d22d0d8c621e57a0c5380753bfa8c"
|
||||
checksum = "8b80bf40380256307b68a3dcbe1b91cac92a533e212b5b635abc3e4525781a0a"
|
||||
dependencies = [
|
||||
"cranelift-bforest",
|
||||
"cranelift-codegen-meta",
|
||||
@ -59,31 +59,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793f6a94a053a55404ea16e1700202a88101672b8cd6b4df63e13cde950852bf"
|
||||
checksum = "703d0ed7d3bc6c7a814ca12858175bf4e93167a3584127858c686e4b5dd6e432"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44aa1846df275bce5eb30379d65964c7afc63c05a117076e62a119c25fe174be"
|
||||
checksum = "80f52311e1c90de12dcf8c4b9999c6ebfd1ed360373e88c357160936844511f6"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3a45d8d6318bf8fc518154d9298eab2a8154ec068a8885ff113f6db8d69bb3a"
|
||||
checksum = "66bc82ef522c1f643baf7d4d40b7c52643ee4549d8960b0e6a047daacb83f897"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e07339bd461766deb7605169de039e01954768ff730fa1254e149001884a8525"
|
||||
checksum = "3cc35e4251864b17515845ba47447bca88fec9ca1a4186b19fe42526e36140e8"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
@ -93,9 +92,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e8f0d60fb5d67f7a1e5c49db38ba96d1c846921faef02085fc5590b74781747"
|
||||
checksum = "93c66d594ad3bfe4e58b1fbd8d17877a7c6564a5f2d6f78cbbf4b0182af1927f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@ -111,21 +110,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "825ac7e0959cbe7ddc9cc21209f0319e611a57f9fcb2b723861fe7ef2017e651"
|
||||
checksum = "bf356697c40232aa09e1e3fb8a350ee894e849ccecc4eac56ff0570a4575c325"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
"cranelift-entity",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e2fca76ff57e0532936a71e3fc267eae6a19a86656716479c66e7f912e3d7b"
|
||||
checksum = "b882b2251c9845d509d92aebfdb6c8bb3b3b48e207ac951f21fbd20cfe7f90b3"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
@ -134,9 +131,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.78.0"
|
||||
version = "0.82.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55500d0fc9bb05c0944fc4506649249d28f55bd4fe95b87f0e55bf41058f0e6d"
|
||||
checksum = "2d3f1a88e654e567d2591169239ed157ab290811a729a6468f53999c01001263"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@ -148,18 +145,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.0"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.25.0"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
@ -182,9 +179,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.112"
|
||||
version = "0.2.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -232,10 +229,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regalloc"
|
||||
version = "0.0.32"
|
||||
name = "once_cell"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6304468554ed921da3d32c355ea107b8d13d7b8996c3adfb7aab48d3bc321f4"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
|
||||
[[package]]
|
||||
name = "regalloc"
|
||||
version = "0.0.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rustc-hash",
|
||||
@ -275,21 +278,22 @@ dependencies = [
|
||||
"indexmap",
|
||||
"libloading",
|
||||
"object",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff"
|
||||
checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
|
@ -8,19 +8,20 @@ crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
# These have to be in sync with each other
|
||||
cranelift-codegen = { version = "0.78.0", features = ["unwind", "all-arch"] }
|
||||
cranelift-frontend = "0.78.0"
|
||||
cranelift-module = "0.78.0"
|
||||
cranelift-native = "0.78.0"
|
||||
cranelift-jit = { version = "0.78.0", optional = true }
|
||||
cranelift-object = "0.78.0"
|
||||
cranelift-codegen = { version = "0.82.1", features = ["unwind", "all-arch"] }
|
||||
cranelift-frontend = "0.82.1"
|
||||
cranelift-module = "0.82.1"
|
||||
cranelift-native = "0.82.1"
|
||||
cranelift-jit = { version = "0.82.1", optional = true }
|
||||
cranelift-object = "0.82.1"
|
||||
target-lexicon = "0.12.0"
|
||||
gimli = { version = "0.25.0", default-features = false, features = ["write"]}
|
||||
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
|
||||
object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
||||
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
|
||||
indexmap = "1.8.0"
|
||||
libloading = { version = "0.6.0", optional = true }
|
||||
once_cell = "1.10.0"
|
||||
smallvec = "1.6.1"
|
||||
|
||||
[patch.crates-io]
|
||||
|
@ -34,15 +34,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@ -56,7 +56,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.66"
|
||||
version = "0.1.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@ -110,9 +112,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
@ -121,9 +123,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
@ -132,9 +134,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.112"
|
||||
version = "0.2.121"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@ -319,9 +321,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
|
@ -14,7 +14,6 @@ compiler_builtins = { version = "0.1.39", default-features = false, features = [
|
||||
rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
|
||||
rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
|
||||
rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
|
||||
compiler_builtins = { path = "./compiler-builtins" }
|
||||
|
||||
[profile.dev]
|
||||
lto = "off"
|
||||
@ -23,3 +22,14 @@ lto = "off"
|
||||
debug = true
|
||||
incremental = true
|
||||
lto = "off"
|
||||
|
||||
# Mandatory for correctly compiling compiler-builtins
|
||||
[profile.dev.package.compiler_builtins]
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
codegen-units = 10000
|
||||
|
||||
[profile.release.package.compiler_builtins]
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
codegen-units = 10000
|
||||
|
@ -49,7 +49,7 @@ pub(crate) fn build_backend(
|
||||
cmd.env("RUSTFLAGS", rustflags);
|
||||
|
||||
eprintln!("[BUILD] rustc_codegen_cranelift");
|
||||
crate::utils::spawn_and_wait(cmd);
|
||||
super::utils::spawn_and_wait(cmd);
|
||||
|
||||
Path::new("target").join(host_triple).join(channel)
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command};
|
||||
|
||||
use crate::rustc_info::{get_file_name, get_rustc_version};
|
||||
use crate::utils::{spawn_and_wait, try_hard_link};
|
||||
use crate::SysrootKind;
|
||||
use super::rustc_info::{get_file_name, get_rustc_version};
|
||||
use super::utils::{spawn_and_wait, try_hard_link};
|
||||
use super::SysrootKind;
|
||||
|
||||
pub(crate) fn build_sysroot(
|
||||
channel: &str,
|
||||
@ -52,7 +52,7 @@ pub(crate) fn build_sysroot(
|
||||
.arg("-g");
|
||||
spawn_and_wait(build_cargo_wrapper_cmd);
|
||||
|
||||
let default_sysroot = crate::rustc_info::get_default_sysroot();
|
||||
let default_sysroot = super::rustc_info::get_default_sysroot();
|
||||
|
||||
let rustlib = target_dir.join("lib").join("rustlib");
|
||||
let host_rustlib_lib = rustlib.join(host_triple).join("lib");
|
||||
@ -167,7 +167,7 @@ fn build_clif_sysroot_for_triple(
|
||||
|
||||
let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
|
||||
|
||||
if !crate::config::get_bool("keep_sysroot") {
|
||||
if !super::config::get_bool("keep_sysroot") {
|
||||
// Cleanup the target dir with the exception of build scripts and the incremental cache
|
||||
for dir in ["build", "deps", "examples", "native"] {
|
||||
if build_dir.join(dir).exists() {
|
||||
|
127
compiler/rustc_codegen_cranelift/build_system/mod.rs
Normal file
127
compiler/rustc_codegen_cranelift/build_system/mod.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
mod build_backend;
|
||||
mod build_sysroot;
|
||||
mod config;
|
||||
mod prepare;
|
||||
mod rustc_info;
|
||||
mod utils;
|
||||
|
||||
fn usage() {
|
||||
eprintln!("Usage:");
|
||||
eprintln!(" ./y.rs prepare");
|
||||
eprintln!(
|
||||
" ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! arg_error {
|
||||
($($err:tt)*) => {{
|
||||
eprintln!($($err)*);
|
||||
usage();
|
||||
std::process::exit(1);
|
||||
}};
|
||||
}
|
||||
|
||||
enum Command {
|
||||
Build,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum SysrootKind {
|
||||
None,
|
||||
Clif,
|
||||
Llvm,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
|
||||
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
|
||||
// The target dir is expected in the default location. Guard against the user changing it.
|
||||
env::set_var("CARGO_TARGET_DIR", "target");
|
||||
|
||||
let mut args = env::args().skip(1);
|
||||
let command = match args.next().as_deref() {
|
||||
Some("prepare") => {
|
||||
if args.next().is_some() {
|
||||
arg_error!("./x.rs prepare doesn't expect arguments");
|
||||
}
|
||||
prepare::prepare();
|
||||
process::exit(0);
|
||||
}
|
||||
Some("build") => Command::Build,
|
||||
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
|
||||
Some(command) => arg_error!("Unknown command {}", command),
|
||||
None => {
|
||||
usage();
|
||||
process::exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
let mut target_dir = PathBuf::from("build");
|
||||
let mut channel = "release";
|
||||
let mut sysroot_kind = SysrootKind::Clif;
|
||||
let mut use_unstable_features = true;
|
||||
while let Some(arg) = args.next().as_deref() {
|
||||
match arg {
|
||||
"--target-dir" => {
|
||||
target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
|
||||
arg_error!("--target-dir requires argument");
|
||||
}))
|
||||
}
|
||||
"--debug" => channel = "debug",
|
||||
"--sysroot" => {
|
||||
sysroot_kind = match args.next().as_deref() {
|
||||
Some("none") => SysrootKind::None,
|
||||
Some("clif") => SysrootKind::Clif,
|
||||
Some("llvm") => SysrootKind::Llvm,
|
||||
Some(arg) => arg_error!("Unknown sysroot kind {}", arg),
|
||||
None => arg_error!("--sysroot requires argument"),
|
||||
}
|
||||
}
|
||||
"--no-unstable-features" => use_unstable_features = false,
|
||||
flag if flag.starts_with("-") => arg_error!("Unknown flag {}", flag),
|
||||
arg => arg_error!("Unexpected argument {}", arg),
|
||||
}
|
||||
}
|
||||
|
||||
let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
|
||||
host_triple
|
||||
} else if let Some(host_triple) = config::get_value("host") {
|
||||
host_triple
|
||||
} else {
|
||||
rustc_info::get_host_triple()
|
||||
};
|
||||
let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") {
|
||||
if target_triple != "" {
|
||||
target_triple
|
||||
} else {
|
||||
host_triple.clone() // Empty target triple can happen on GHA
|
||||
}
|
||||
} else if let Some(target_triple) = config::get_value("target") {
|
||||
target_triple
|
||||
} else {
|
||||
host_triple.clone()
|
||||
};
|
||||
|
||||
if target_triple.ends_with("-msvc") {
|
||||
eprintln!("The MSVC toolchain is not yet supported by rustc_codegen_cranelift.");
|
||||
eprintln!("Switch to the MinGW toolchain for Windows support.");
|
||||
eprintln!("Hint: You can use `rustup set default-host x86_64-pc-windows-gnu` to");
|
||||
eprintln!("set the global default target to MinGW");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let cg_clif_build_dir =
|
||||
build_backend::build_backend(channel, &host_triple, use_unstable_features);
|
||||
build_sysroot::build_sysroot(
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&target_dir,
|
||||
cg_clif_build_dir,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
);
|
||||
}
|
@ -5,8 +5,8 @@ use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
|
||||
use crate::utils::{copy_dir_recursively, spawn_and_wait};
|
||||
use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
|
||||
use super::utils::{copy_dir_recursively, spawn_and_wait};
|
||||
|
||||
pub(crate) fn prepare() {
|
||||
prepare_sysroot();
|
||||
@ -14,29 +14,33 @@ pub(crate) fn prepare() {
|
||||
eprintln!("[INSTALL] hyperfine");
|
||||
Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
|
||||
|
||||
clone_repo(
|
||||
clone_repo_shallow_github(
|
||||
"rand",
|
||||
"rust-random",
|
||||
"rand",
|
||||
"https://github.com/rust-random/rand.git",
|
||||
"0f933f9c7176e53b2a3c7952ded484e1783f0bf1",
|
||||
);
|
||||
apply_patches("rand", Path::new("rand"));
|
||||
|
||||
clone_repo(
|
||||
clone_repo_shallow_github(
|
||||
"regex",
|
||||
"rust-lang",
|
||||
"regex",
|
||||
"https://github.com/rust-lang/regex.git",
|
||||
"341f207c1071f7290e3f228c710817c280c8dca1",
|
||||
);
|
||||
|
||||
clone_repo(
|
||||
clone_repo_shallow_github(
|
||||
"portable-simd",
|
||||
"rust-lang",
|
||||
"portable-simd",
|
||||
"https://github.com/rust-lang/portable-simd",
|
||||
"b8d6b6844602f80af79cd96401339ec594d472d8",
|
||||
);
|
||||
apply_patches("portable-simd", Path::new("portable-simd"));
|
||||
|
||||
clone_repo(
|
||||
clone_repo_shallow_github(
|
||||
"simple-raytracer",
|
||||
"ebobby",
|
||||
"simple-raytracer",
|
||||
"https://github.com/ebobby/simple-raytracer",
|
||||
"804a7a21b9e673a482797aa289a18ed480e4d813",
|
||||
);
|
||||
|
||||
@ -74,29 +78,12 @@ fn prepare_sysroot() {
|
||||
git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
|
||||
spawn_and_wait(git_init_cmd);
|
||||
|
||||
let mut git_add_cmd = Command::new("git");
|
||||
git_add_cmd.arg("add").arg(".").current_dir(&sysroot_src);
|
||||
spawn_and_wait(git_add_cmd);
|
||||
|
||||
let mut git_commit_cmd = Command::new("git");
|
||||
git_commit_cmd
|
||||
.arg("commit")
|
||||
.arg("-m")
|
||||
.arg("Initial commit")
|
||||
.arg("-q")
|
||||
.current_dir(&sysroot_src);
|
||||
spawn_and_wait(git_commit_cmd);
|
||||
init_git_repo(&sysroot_src);
|
||||
|
||||
apply_patches("sysroot", &sysroot_src);
|
||||
|
||||
clone_repo(
|
||||
"build_sysroot/compiler-builtins",
|
||||
"https://github.com/rust-lang/compiler-builtins.git",
|
||||
"0.1.66",
|
||||
);
|
||||
apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins"));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn clone_repo(target_dir: &str, repo: &str, rev: &str) {
|
||||
eprintln!("[CLONE] {}", repo);
|
||||
// Ignore exit code as the repo may already have been checked out
|
||||
@ -111,6 +98,57 @@ fn clone_repo(target_dir: &str, repo: &str, rev: &str) {
|
||||
spawn_and_wait(checkout_cmd);
|
||||
}
|
||||
|
||||
fn clone_repo_shallow_github(target_dir: &str, username: &str, repo: &str, rev: &str) {
|
||||
if cfg!(windows) {
|
||||
// Older windows doesn't have tar or curl by default. Fall back to using git.
|
||||
clone_repo(target_dir, &format!("https://github.com/{}/{}.git", username, repo), rev);
|
||||
return;
|
||||
}
|
||||
|
||||
let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", username, repo, rev);
|
||||
let archive_file = format!("{}.tar.gz", rev);
|
||||
let archive_dir = format!("{}-{}", repo, rev);
|
||||
|
||||
eprintln!("[DOWNLOAD] {}/{} from {}", username, repo, archive_url);
|
||||
|
||||
// Remove previous results if they exists
|
||||
let _ = std::fs::remove_file(&archive_file);
|
||||
let _ = std::fs::remove_dir_all(&archive_dir);
|
||||
let _ = std::fs::remove_dir_all(target_dir);
|
||||
|
||||
// Download zip archive
|
||||
let mut download_cmd = Command::new("curl");
|
||||
download_cmd.arg("--location").arg("--output").arg(&archive_file).arg(archive_url);
|
||||
spawn_and_wait(download_cmd);
|
||||
|
||||
// Unpack tar archive
|
||||
let mut unpack_cmd = Command::new("tar");
|
||||
unpack_cmd.arg("xf").arg(&archive_file);
|
||||
spawn_and_wait(unpack_cmd);
|
||||
|
||||
// Rename unpacked dir to the expected name
|
||||
std::fs::rename(archive_dir, target_dir).unwrap();
|
||||
|
||||
init_git_repo(Path::new(target_dir));
|
||||
|
||||
// Cleanup
|
||||
std::fs::remove_file(archive_file).unwrap();
|
||||
}
|
||||
|
||||
fn init_git_repo(repo_dir: &Path) {
|
||||
let mut git_init_cmd = Command::new("git");
|
||||
git_init_cmd.arg("init").arg("-q").current_dir(repo_dir);
|
||||
spawn_and_wait(git_init_cmd);
|
||||
|
||||
let mut git_add_cmd = Command::new("git");
|
||||
git_add_cmd.arg("add").arg(".").current_dir(repo_dir);
|
||||
spawn_and_wait(git_add_cmd);
|
||||
|
||||
let mut git_commit_cmd = Command::new("git");
|
||||
git_commit_cmd.arg("commit").arg("-m").arg("Initial commit").arg("-q").current_dir(repo_dir);
|
||||
spawn_and_wait(git_commit_cmd);
|
||||
}
|
||||
|
||||
fn get_patches(crate_name: &str) -> Vec<OsString> {
|
||||
let mut patches: Vec<_> = fs::read_dir("patches")
|
||||
.unwrap()
|
||||
|
@ -2,5 +2,5 @@
|
||||
set -e
|
||||
|
||||
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
|
||||
rm -rf target/ build/ perf.data{,.old}
|
||||
rm -rf target/ build/ perf.data{,.old} y.bin
|
||||
rm -rf rand/ regex/ simple-raytracer/ portable-simd/
|
||||
|
@ -8,33 +8,21 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![no_std]
|
||||
#![feature(allocator_api, rustc_private)]
|
||||
#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
|
||||
|
||||
// The minimum alignment guaranteed by the architecture. This value is used to
|
||||
// add fast paths for low alignment values.
|
||||
#[cfg(all(any(target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "mips",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64")))]
|
||||
const MIN_ALIGN: usize = 8;
|
||||
#[cfg(all(any(target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "sparc64")))]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
|
||||
pub struct System;
|
||||
|
||||
#[cfg(any(windows, unix, target_os = "redox"))]
|
||||
mod realloc_fallback {
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::cmp;
|
||||
use core::ptr;
|
||||
impl super::System {
|
||||
pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
|
||||
new_size: usize) -> *mut u8 {
|
||||
pub(crate) unsafe fn realloc_fallback(
|
||||
&self,
|
||||
ptr: *mut u8,
|
||||
old_layout: Layout,
|
||||
new_size: usize,
|
||||
) -> *mut u8 {
|
||||
// Docs for GlobalAlloc::realloc require this to be valid:
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
|
||||
let new_ptr = GlobalAlloc::alloc(self, new_layout);
|
||||
@ -49,97 +37,47 @@ mod realloc_fallback {
|
||||
}
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
mod platform {
|
||||
extern crate libc;
|
||||
use core::ptr;
|
||||
use MIN_ALIGN;
|
||||
use System;
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::ffi::c_void;
|
||||
use core::ptr;
|
||||
use System;
|
||||
extern "C" {
|
||||
fn posix_memalign(memptr: *mut *mut c_void, align: usize, size: usize) -> i32;
|
||||
fn free(p: *mut c_void);
|
||||
}
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
|
||||
libc::malloc(layout.size()) as *mut u8
|
||||
} else {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if layout.align() > (1 << 31) {
|
||||
return ptr::null_mut()
|
||||
}
|
||||
}
|
||||
aligned_malloc(&layout)
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
|
||||
libc::calloc(layout.size(), 1) as *mut u8
|
||||
} else {
|
||||
let ptr = self.alloc(layout.clone());
|
||||
if !ptr.is_null() {
|
||||
ptr::write_bytes(ptr, 0, layout.size());
|
||||
}
|
||||
ptr
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
libc::free(ptr as *mut libc::c_void)
|
||||
free(ptr as *mut c_void)
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
|
||||
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
|
||||
} else {
|
||||
self.realloc_fallback(ptr, layout, new_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "hermit",
|
||||
target_os = "redox",
|
||||
target_os = "solaris"))]
|
||||
#[inline]
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
// On android we currently target API level 9 which unfortunately
|
||||
// doesn't have the `posix_memalign` API used below. Instead we use
|
||||
// `memalign`, but this unfortunately has the property on some systems
|
||||
// where the memory returned cannot be deallocated by `free`!
|
||||
//
|
||||
// Upon closer inspection, however, this appears to work just fine with
|
||||
// Android, so for this platform we should be fine to call `memalign`
|
||||
// (which is present in API level 9). Some helpful references could
|
||||
// possibly be chromium using memalign [1], attempts at documenting that
|
||||
// memalign + free is ok [2] [3], or the current source of chromium
|
||||
// which still uses memalign on android [4].
|
||||
//
|
||||
// [1]: https://codereview.chromium.org/10796020/
|
||||
// [2]: https://code.google.com/p/android/issues/detail?id=35391
|
||||
// [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
|
||||
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
|
||||
// /memory/aligned_memory.cc
|
||||
libc::memalign(layout.align(), layout.size()) as *mut u8
|
||||
}
|
||||
#[cfg(not(any(target_os = "android",
|
||||
target_os = "hermit",
|
||||
target_os = "redox",
|
||||
target_os = "solaris")))]
|
||||
#[inline]
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
let mut out = ptr::null_mut();
|
||||
let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
|
||||
if ret != 0 {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
out as *mut u8
|
||||
}
|
||||
let ret = posix_memalign(&mut out, layout.align(), layout.size());
|
||||
if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[allow(nonstandard_style)]
|
||||
mod platform {
|
||||
use MIN_ALIGN;
|
||||
use System;
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use System;
|
||||
type LPVOID = *mut u8;
|
||||
type HANDLE = LPVOID;
|
||||
type SIZE_T = usize;
|
||||
@ -165,18 +103,9 @@ mod platform {
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
|
||||
let ptr = if layout.align() <= MIN_ALIGN {
|
||||
HeapAlloc(GetProcessHeap(), flags, layout.size())
|
||||
} else {
|
||||
let size = layout.size() + layout.align();
|
||||
let ptr = HeapAlloc(GetProcessHeap(), flags, size);
|
||||
if ptr.is_null() {
|
||||
ptr
|
||||
} else {
|
||||
align_ptr(ptr, layout.align())
|
||||
}
|
||||
};
|
||||
ptr as *mut u8
|
||||
(if ptr.is_null() { ptr } else { align_ptr(ptr, layout.align()) }) as *mut u8
|
||||
}
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
@ -189,24 +118,13 @@ mod platform {
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
if layout.align() <= MIN_ALIGN {
|
||||
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}",
|
||||
GetLastError());
|
||||
} else {
|
||||
let header = get_header(ptr);
|
||||
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}",
|
||||
GetLastError());
|
||||
}
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN {
|
||||
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
|
||||
} else {
|
||||
self.realloc_fallback(ptr, layout, new_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Adapted from rustc run-pass test suite
|
||||
|
||||
#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::{
|
||||
ops::{Deref, CoerceUnsized, DispatchFromDyn},
|
||||
@ -37,7 +36,7 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
|
||||
|
||||
trait Trait {
|
||||
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
|
||||
// without unsized_locals), but wrappers arond `Self` currently are not.
|
||||
// without unsized_locals), but wrappers around `Self` currently are not.
|
||||
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
|
||||
// fn wrapper(self: Wrapper<Self>) -> i32;
|
||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
||||
|
@ -1,7 +1,14 @@
|
||||
#![feature(
|
||||
no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
|
||||
untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits,
|
||||
thread_local,
|
||||
no_core,
|
||||
lang_items,
|
||||
intrinsics,
|
||||
unboxed_closures,
|
||||
extern_types,
|
||||
decl_macro,
|
||||
rustc_attrs,
|
||||
transparent_unions,
|
||||
auto_traits,
|
||||
thread_local
|
||||
)]
|
||||
#![no_core]
|
||||
#![allow(dead_code)]
|
||||
@ -55,6 +62,7 @@ unsafe impl Copy for i16 {}
|
||||
unsafe impl Copy for i32 {}
|
||||
unsafe impl Copy for isize {}
|
||||
unsafe impl Copy for f32 {}
|
||||
unsafe impl Copy for f64 {}
|
||||
unsafe impl Copy for char {}
|
||||
unsafe impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
unsafe impl<T: ?Sized> Copy for *const T {}
|
||||
@ -483,8 +491,17 @@ pub trait Deref {
|
||||
fn deref(&self) -> &Self::Target;
|
||||
}
|
||||
|
||||
pub struct Unique<T: ?Sized> {
|
||||
pub pointer: *const T,
|
||||
pub _marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T: ?Sized>(*mut T);
|
||||
pub struct Box<T: ?Sized>(Unique<T>, ());
|
||||
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
|
||||
|
||||
@ -508,8 +525,8 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
|
||||
}
|
||||
|
||||
#[lang = "box_free"]
|
||||
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
|
||||
libc::free(ptr as *mut u8);
|
||||
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, alloc: ()) {
|
||||
libc::free(ptr.pointer as *mut u8);
|
||||
}
|
||||
|
||||
#[lang = "drop"]
|
||||
|
@ -7,10 +7,6 @@ extern crate mini_core;
|
||||
use mini_core::*;
|
||||
use mini_core::libc::*;
|
||||
|
||||
unsafe extern "C" fn my_puts(s: *const i8) {
|
||||
puts(s);
|
||||
}
|
||||
|
||||
macro_rules! assert {
|
||||
($e:expr) => {
|
||||
if !$e {
|
||||
@ -105,12 +101,6 @@ fn start<T: Termination + 'static>(
|
||||
static mut NUM: u8 = 6 * 7;
|
||||
static NUM_REF: &'static u8 = unsafe { &NUM };
|
||||
|
||||
struct Unique<T: ?Sized> {
|
||||
pointer: *const T,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
|
||||
unsafe fn zeroed<T>() -> T {
|
||||
let mut uninit = MaybeUninit { uninit: () };
|
||||
|
@ -1,48 +0,0 @@
|
||||
From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
|
||||
From: bjorn3 <bjorn3@users.noreply.github.com>
|
||||
Date: Thu, 18 Feb 2021 18:30:55 +0100
|
||||
Subject: [PATCH] Disable 128bit atomic operations
|
||||
|
||||
Cranelift doesn't support them yet
|
||||
---
|
||||
src/mem/mod.rs | 12 ------------
|
||||
1 file changed, 12 deletions(-)
|
||||
|
||||
diff --git a/src/mem/mod.rs b/src/mem/mod.rs
|
||||
index 107762c..2d1ae10 100644
|
||||
--- a/src/mem/mod.rs
|
||||
+++ b/src/mem/mod.rs
|
||||
@@ -137,10 +137,6 @@ intrinsics! {
|
||||
pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
|
||||
memcpy_element_unordered_atomic(dest, src, bytes);
|
||||
}
|
||||
- #[cfg(target_has_atomic_load_store = "128")]
|
||||
- pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
|
||||
- memcpy_element_unordered_atomic(dest, src, bytes);
|
||||
- }
|
||||
|
||||
#[cfg(target_has_atomic_load_store = "8")]
|
||||
pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
|
||||
@@ -158,10 +154,6 @@ intrinsics! {
|
||||
pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
|
||||
memmove_element_unordered_atomic(dest, src, bytes);
|
||||
}
|
||||
- #[cfg(target_has_atomic_load_store = "128")]
|
||||
- pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
|
||||
- memmove_element_unordered_atomic(dest, src, bytes);
|
||||
- }
|
||||
|
||||
#[cfg(target_has_atomic_load_store = "8")]
|
||||
pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
|
||||
@@ -179,8 +171,4 @@ intrinsics! {
|
||||
pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
|
||||
memset_element_unordered_atomic(s, c, bytes);
|
||||
}
|
||||
- #[cfg(target_has_atomic_load_store = "128")]
|
||||
- pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
|
||||
- memset_element_unordered_atomic(s, c, bytes);
|
||||
- }
|
||||
}
|
||||
--
|
||||
2.26.2.7.g19db9cfb68
|
||||
|
@ -1,23 +0,0 @@
|
||||
From 9c5663e36391fa20becf84f3af2e82afa5bb720b Mon Sep 17 00:00:00 2001
|
||||
From: bjorn3 <bjorn3@users.noreply.github.com>
|
||||
Date: Sat, 15 Aug 2020 19:56:03 +0200
|
||||
Subject: [PATCH] [rand] Enable c2-chacha simd feature
|
||||
|
||||
---
|
||||
rand_chacha/Cargo.toml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/rand_chacha/Cargo.toml b/rand_chacha/Cargo.toml
|
||||
index 9190b7f..872cca2 100644
|
||||
--- a/rand_chacha/Cargo.toml
|
||||
+++ b/rand_chacha/Cargo.toml
|
||||
@@ -24,5 +24,5 @@ ppv-lite86 = { version = "0.2.8", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
-std = ["ppv-lite86/std"]
|
||||
+std = ["ppv-lite86/std", "ppv-lite86/simd"]
|
||||
simd = [] # deprecated
|
||||
--
|
||||
2.20.1
|
||||
|
@ -4,27 +4,18 @@ Date: Sat, 15 Aug 2020 20:04:38 +0200
|
||||
Subject: [PATCH] [rand] Disable failing test
|
||||
|
||||
---
|
||||
src/distributions/uniform.rs | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
src/distributions/uniform.rs | 1 +
|
||||
1 file changed, 1 insertion(+), 0 deletions(-)
|
||||
|
||||
diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
|
||||
index 480b859..c80bb6f 100644
|
||||
--- a/src/distributions/uniform.rs
|
||||
+++ b/src/distributions/uniform.rs
|
||||
@@ -1085,7 +1085,7 @@ mod tests {
|
||||
_ => panic!("`UniformDurationMode` was not serialized/deserialized correctly")
|
||||
}
|
||||
}
|
||||
-
|
||||
+
|
||||
#[test]
|
||||
#[cfg(feature = "serde1")]
|
||||
fn test_uniform_serialization() {
|
||||
@@ -1314,6 +1314,7 @@ mod tests {
|
||||
not(target_arch = "wasm32"),
|
||||
not(target_arch = "asmjs")
|
||||
))]
|
||||
+ #[ignore] // FIXME
|
||||
+ #[ignore] // Requires unwinding
|
||||
fn test_float_assertions() {
|
||||
use super::SampleUniform;
|
||||
use std::panic::catch_unwind;
|
||||
|
@ -18,66 +18,17 @@ new file mode 100644
|
||||
index 0000000..46fd999
|
||||
--- /dev/null
|
||||
+++ b/library/core/tests/Cargo.toml
|
||||
@@ -0,0 +1,8 @@
|
||||
@@ -0,0 +1,11 @@
|
||||
+[package]
|
||||
+name = "core"
|
||||
+version = "0.0.0"
|
||||
+edition = "2018"
|
||||
+edition = "2021"
|
||||
+
|
||||
+[lib]
|
||||
+name = "coretests"
|
||||
+path = "lib.rs"
|
||||
diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
|
||||
index a35897e..f0bf645 100644
|
||||
--- a/library/core/tests/num/flt2dec/mod.rs
|
||||
+++ b/library/core/tests/num/flt2dec/mod.rs
|
||||
@@ -13,7 +13,6 @@ mod strategy {
|
||||
mod dragon;
|
||||
mod grisu;
|
||||
}
|
||||
-mod random;
|
||||
|
||||
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
|
||||
match decode(v).1 {
|
||||
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
|
||||
index 1a6be3a..42dbd59 100644
|
||||
--- a/library/core/tests/ptr.rs
|
||||
+++ b/library/core/tests/ptr.rs
|
||||
@@ -250,6 +250,7 @@ fn test_unsized_nonnull() {
|
||||
assert!(ys == zs);
|
||||
}
|
||||
|
||||
+/*
|
||||
#[test]
|
||||
#[allow(warnings)]
|
||||
// Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
|
||||
@@ -277,6 +277,7 @@ pub fn test_variadic_fnptr() {
|
||||
let mut s = SipHasher::new();
|
||||
assert_eq!(p.hash(&mut s), q.hash(&mut s));
|
||||
}
|
||||
+*/
|
||||
|
||||
#[test]
|
||||
fn write_unaligned_drop() {
|
||||
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
|
||||
index 6609bc3..241b497 100644
|
||||
--- a/library/core/tests/slice.rs
|
||||
+++ b/library/core/tests/slice.rs
|
||||
@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() {
|
||||
}
|
||||
}
|
||||
|
||||
+/*
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn sort_unstable() {
|
||||
@@ -1394,6 +1395,7 @@ fn partition_at_index() {
|
||||
v.select_nth_unstable(0);
|
||||
assert!(v == [0xDEADBEEF]);
|
||||
}
|
||||
+*/
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "index 0 greater than length of slice")]
|
||||
+
|
||||
+[dependencies]
|
||||
+rand = "0.7"
|
||||
--
|
||||
2.21.0 (Apple Git-122)
|
||||
|
@ -8,7 +8,6 @@ Cranelift doesn't support them yet
|
||||
library/core/src/panic/unwind_safe.rs | 6 -----
|
||||
library/core/src/sync/atomic.rs | 38 ---------------------------
|
||||
library/core/tests/atomic.rs | 4 ---
|
||||
library/std/src/time/monotonic.rs | 6 +++--
|
||||
4 files changed, 4 insertions(+), 50 deletions(-)
|
||||
|
||||
diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
|
||||
@ -99,38 +98,6 @@ index b735957..ea728b6 100644
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
|
||||
index fa96b7a..2854f9c 100644
|
||||
--- a/library/std/src/time/monotonic.rs
|
||||
+++ b/library/std/src/time/monotonic.rs
|
||||
@@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
|
||||
inner::monotonize(raw)
|
||||
}
|
||||
|
||||
-#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))]
|
||||
+#[cfg(target_has_atomic = "64")]
|
||||
pub mod inner {
|
||||
use crate::sync::atomic::AtomicU64;
|
||||
use crate::sync::atomic::Ordering::*;
|
||||
@@ -70,6 +70,7 @@ pub mod inner {
|
||||
}
|
||||
}
|
||||
|
||||
+/*
|
||||
#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))]
|
||||
pub mod inner {
|
||||
use crate::sync::atomic::AtomicU128;
|
||||
@@ -94,8 +95,9 @@ pub mod inner {
|
||||
ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
|
||||
}
|
||||
}
|
||||
+*/
|
||||
|
||||
-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
|
||||
+#[cfg(not(target_has_atomic = "64"))]
|
||||
pub mod inner {
|
||||
use crate::cmp;
|
||||
use crate::sys::time;
|
||||
--
|
||||
2.26.2.7.g19db9cfb68
|
||||
|
||||
|
@ -1,30 +1,48 @@
|
||||
From 0ffdd8eda8df364391c8ac6e1ce92c73ba9254d4 Mon Sep 17 00:00:00 2001
|
||||
From eb703e627e7a84f1cd8d0d87f0f69da1f0acf765 Mon Sep 17 00:00:00 2001
|
||||
From: bjorn3 <bjorn3@users.noreply.github.com>
|
||||
Date: Fri, 3 Dec 2021 12:16:30 +0100
|
||||
Subject: [PATCH] Disable long running tests
|
||||
|
||||
---
|
||||
library/core/tests/slice.rs | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
library/core/tests/slice.rs | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
|
||||
index 2c8f00a..44847ee 100644
|
||||
index 8402833..84592e0 100644
|
||||
--- a/library/core/tests/slice.rs
|
||||
+++ b/library/core/tests/slice.rs
|
||||
@@ -2332,7 +2332,8 @@ macro_rules! empty_max_mut {
|
||||
};
|
||||
@@ -1809,6 +1809,7 @@ fn sort_unstable() {
|
||||
assert!(v == [0xDEADBEEF]);
|
||||
}
|
||||
|
||||
+/*
|
||||
#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
|
||||
take_tests! {
|
||||
slice: &[(); usize::MAX], method: take,
|
||||
(take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
|
||||
@@ -2345,3 +2347,4 @@ take_tests! {
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
@@ -1914,6 +1915,7 @@ fn select_nth_unstable() {
|
||||
v.select_nth_unstable(0);
|
||||
assert!(v == [0xDEADBEEF]);
|
||||
}
|
||||
+*/
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "index 0 greater than length of slice")]
|
||||
@@ -2462,6 +2462,7 @@ take_tests! {
|
||||
#[cfg(not(miri))] // unused in Miri
|
||||
const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
|
||||
|
||||
+/*
|
||||
// can't be a constant due to const mutability rules
|
||||
#[cfg(not(miri))] // unused in Miri
|
||||
macro_rules! empty_max_mut {
|
||||
@@ -2485,6 +2486,7 @@ take_tests! {
|
||||
(take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
|
||||
(take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
|
||||
}
|
||||
+*/
|
||||
|
||||
#[test]
|
||||
fn test_slice_from_ptr_range() {
|
||||
--
|
||||
2.26.2.7.g19db9cfb68
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2021-12-30"
|
||||
channel = "nightly-2022-03-19"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
@ -11,7 +11,7 @@ case $1 in
|
||||
sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain
|
||||
rustup component add rustfmt || true
|
||||
|
||||
echo "=> Uninstalling all old nighlies"
|
||||
echo "=> Uninstalling all old nightlies"
|
||||
for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do
|
||||
rustup toolchain uninstall "$nightly"
|
||||
done
|
||||
|
@ -12,18 +12,6 @@ git checkout -- .
|
||||
git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
|
||||
|
||||
git apply - <<EOF
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 5bd1147cad5..10d68a2ff14 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -111,5 +111,7 @@ rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' }
|
||||
rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' }
|
||||
rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' }
|
||||
|
||||
+compiler_builtins = { path = "../build_sysroot/compiler-builtins" }
|
||||
+
|
||||
[patch."https://github.com/rust-lang/rust-clippy"]
|
||||
clippy_lints = { path = "src/tools/clippy/clippy_lints" }
|
||||
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
|
||||
index d95b5b7f17f..00b6f0e3635 100644
|
||||
--- a/library/alloc/Cargo.toml
|
||||
@ -38,9 +26,43 @@ index d95b5b7f17f..00b6f0e3635 100644
|
||||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
rand_xorshift = "0.2"
|
||||
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
|
||||
index 887d27fd6dca4..2c2239f2b83d1 100644
|
||||
--- a/src/tools/compiletest/src/header.rs
|
||||
+++ b/src/tools/compiletest/src/header.rs
|
||||
@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
|
||||
cfg: Option<&str>,
|
||||
) -> test::TestDesc {
|
||||
let mut ignore = false;
|
||||
#[cfg(not(bootstrap))]
|
||||
- let ignore_message: Option<String> = None;
|
||||
+ let ignore_message: Option<&str> = None;
|
||||
let mut should_fail = false;
|
||||
|
||||
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
|
||||
|
||||
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
|
||||
index 8431aa7b818..a3ff7e68ce5 100644
|
||||
--- a/src/tools/compiletest/src/runtest.rs
|
||||
+++ b/src/tools/compiletest/src/runtest.rs
|
||||
@@ -3489,11 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
|
||||
.join("library");
|
||||
normalize_path(&src_dir, "$(echo '$SRC_DIR')");
|
||||
|
||||
- if let Some(virtual_rust_source_base_dir) =
|
||||
- option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
|
||||
- {
|
||||
- normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
|
||||
- }
|
||||
+ normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
|
||||
|
||||
// Paths into the build directory
|
||||
let test_build_dir = &self.config.build_base;
|
||||
EOF
|
||||
|
||||
cat > config.toml <<EOF
|
||||
changelog-seen = 2
|
||||
|
||||
[llvm]
|
||||
ninja = false
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user