New upstream version 1.61.0+dfsg1

This commit is contained in:
Fabian Grünbichler 2022-07-28 14:14:48 +02:00
parent 5099ac242f
commit 5e7ed085d1
4979 changed files with 744214 additions and 60462 deletions

129
Cargo.lock generated
View File

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

View File

@ -1,4 +1,5 @@
[workspace]
default-members = ["src/bootstrap"]
members = [
"src/bootstrap",
"compiler/rustc",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,
// 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(),
// 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));
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;
}
}
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
fn visit_attribute(&mut self, _: &'a Attribute) {
// We do not want to lower expressions that appear in attributes,
// as they are not accessible to the rest of the HIR.
}
fn visit_item(&mut self, item: &'a Item) {
let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
hir::OwnerNode::Item(node)
});
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),
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),
}
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
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.

View File

@ -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(&param);
}
@ -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),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&param_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, &note_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(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2021-12-30"
channel = "nightly-2022-03-19"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View File

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

View File

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