commit
20180540e6
703 changed files with 10302 additions and 5405 deletions
1
.mailmap
1
.mailmap
|
|
@ -15,6 +15,7 @@ Adrien Tétar <adri-from-59@hotmail.fr>
|
|||
Ahmed Charles <ahmedcharles@gmail.com> <acharles@outlook.com>
|
||||
Alan Egerton <eggyal@gmail.com>
|
||||
Alan Stoate <alan.stoate@gmail.com>
|
||||
Albert Larsan <albert.larsan@gmail.com> Albert Larsan <74931857+albertlarsan68@users.noreply.github.com>
|
||||
Alessandro Decina <alessandro.d@gmail.com>
|
||||
Alex Burka <durka42+github@gmail.com> Alex Burka <aburka@seas.upenn.edu>
|
||||
Alex Hansen <ahansen2@trinity.edu>
|
||||
|
|
|
|||
34
Cargo.lock
34
Cargo.lock
|
|
@ -351,7 +351,7 @@ dependencies = [
|
|||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
"clap 4.0.32",
|
||||
"clap 4.1.1",
|
||||
"crates-io",
|
||||
"curl",
|
||||
"curl-sys",
|
||||
|
|
@ -551,9 +551,9 @@ version = "0.1.0"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.76"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
|
||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
|
@ -655,12 +655,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.0.32"
|
||||
version = "4.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
|
||||
checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive 4.0.21",
|
||||
"clap_derive 4.1.0",
|
||||
"clap_lex 0.3.0",
|
||||
"is-terminal",
|
||||
"once_cell",
|
||||
|
|
@ -675,7 +675,7 @@ version = "4.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
|
||||
dependencies = [
|
||||
"clap 4.0.32",
|
||||
"clap 4.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -693,9 +693,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.0.21"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
|
||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
|
@ -1799,9 +1799,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b"
|
||||
checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
|
|
@ -2294,7 +2294,7 @@ name = "jsondoclint"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
"clap 4.1.1",
|
||||
"fs-err",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
|
|
@ -2365,9 +2365,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.14.1+1.5.0"
|
||||
version = "0.14.2+1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17"
|
||||
checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -2557,7 +2557,7 @@ dependencies = [
|
|||
"ammonia",
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap 4.0.32",
|
||||
"clap 4.1.1",
|
||||
"clap_complete",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.10.0",
|
||||
|
|
@ -3528,7 +3528,7 @@ dependencies = [
|
|||
name = "rustbook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 4.0.32",
|
||||
"clap 4.1.1",
|
||||
"env_logger 0.7.1",
|
||||
"mdbook",
|
||||
]
|
||||
|
|
@ -4783,6 +4783,7 @@ dependencies = [
|
|||
"rustc_middle",
|
||||
"rustc_parse_format",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
|
|
@ -5607,6 +5608,7 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
"semver",
|
||||
"termcolor",
|
||||
"walkdir",
|
||||
]
|
||||
|
|
|
|||
163
README.md
163
README.md
|
|
@ -3,10 +3,11 @@
|
|||
This is the main source code repository for [Rust]. It contains the compiler,
|
||||
standard library, and documentation.
|
||||
|
||||
[Rust]: https://www.rust-lang.org
|
||||
[Rust]: https://www.rust-lang.org/
|
||||
|
||||
**Note: this README is for _users_ rather than _contributors_.**
|
||||
If you wish to _contribute_ to the compiler, you should read [CONTRIBUTING.md](CONTRIBUTING.md) instead.
|
||||
If you wish to _contribute_ to the compiler, you should read
|
||||
[CONTRIBUTING.md](CONTRIBUTING.md) instead.
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
|
@ -20,13 +21,15 @@ Read ["Installation"] from [The Book].
|
|||
The Rust build system uses a Python script called `x.py` to build the compiler,
|
||||
which manages the bootstrapping process. It lives at the root of the project.
|
||||
|
||||
The `x.py` command can be run directly on most Unix systems in the following format:
|
||||
The `x.py` command can be run directly on most Unix systems in the following
|
||||
format:
|
||||
|
||||
```sh
|
||||
./x.py <subcommand> [flags]
|
||||
```
|
||||
|
||||
This is how the documentation and examples assume you are running `x.py`. Some alternative ways are:
|
||||
This is how the documentation and examples assume you are running `x.py`.
|
||||
Some alternative ways are:
|
||||
|
||||
```sh
|
||||
# On a Unix shell if you don't have the necessary `python3` command
|
||||
|
|
@ -39,8 +42,8 @@ x.py <subcommand> [flags]
|
|||
python x.py <subcommand> [flags]
|
||||
```
|
||||
|
||||
More information about `x.py` can be found
|
||||
by running it with the `--help` flag or reading the [rustc dev guide][rustcguidebuild].
|
||||
More information about `x.py` can be found by running it with the `--help` flag
|
||||
or reading the [rustc dev guide][rustcguidebuild].
|
||||
|
||||
[gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
|
||||
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
|
||||
|
|
@ -49,24 +52,29 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide
|
|||
|
||||
Make sure you have installed the dependencies:
|
||||
|
||||
* `python` 3 or 2.7
|
||||
* `git`
|
||||
* A C compiler (when building for the host, `cc` is enough; cross-compiling may need additional compilers)
|
||||
* `curl` (not needed on Windows)
|
||||
* `pkg-config` if you are compiling on Linux and targeting Linux
|
||||
* `libiconv` (already included with glibc on Debian-based distros)
|
||||
* `python` 3 or 2.7
|
||||
* `git`
|
||||
* A C compiler (when building for the host, `cc` is enough; cross-compiling may
|
||||
need additional compilers)
|
||||
* `curl` (not needed on Windows)
|
||||
* `pkg-config` if you are compiling on Linux and targeting Linux
|
||||
* `libiconv` (already included with glibc on Debian-based distros)
|
||||
|
||||
To build cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on most Unix distros).
|
||||
To build Cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on
|
||||
most Unix distros).
|
||||
|
||||
If building LLVM from source, you'll need additional tools:
|
||||
|
||||
* `g++`, `clang++`, or MSVC with versions listed on
|
||||
[LLVM's documentation](https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library)
|
||||
* `ninja`, or GNU `make` 3.81 or later (ninja is recommended, especially on Windows)
|
||||
* `ninja`, or GNU `make` 3.81 or later (Ninja is recommended, especially on
|
||||
Windows)
|
||||
* `cmake` 3.13.4 or later
|
||||
* `libstdc++-static` may be required on some Linux distributions such as Fedora and Ubuntu
|
||||
* `libstdc++-static` may be required on some Linux distributions such as Fedora
|
||||
and Ubuntu
|
||||
|
||||
On tier 1 or tier 2 with host tools platforms, you can also choose to download LLVM by setting `llvm.download-ci-llvm = true`.
|
||||
On tier 1 or tier 2 with host tools platforms, you can also choose to download
|
||||
LLVM by setting `llvm.download-ci-llvm = true`.
|
||||
Otherwise, you'll need LLVM installed and `llvm-config` in your path.
|
||||
See [the rustc-dev-guide for more info][sysllvm].
|
||||
|
||||
|
|
@ -86,34 +94,37 @@ See [the rustc-dev-guide for more info][sysllvm].
|
|||
|
||||
2. Configure the build settings:
|
||||
|
||||
The Rust build system uses a file named `config.toml` in the root of the
|
||||
source tree to determine various configuration settings for the build.
|
||||
Set up the defaults intended for distros to get started. You can see a full list of options
|
||||
in `config.toml.example`.
|
||||
The Rust build system uses a file named `config.toml` in the root of the
|
||||
source tree to determine various configuration settings for the build.
|
||||
Set up the defaults intended for distros to get started. You can see a full
|
||||
list of options in `config.toml.example`.
|
||||
|
||||
```sh
|
||||
printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml
|
||||
```
|
||||
```sh
|
||||
printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml
|
||||
```
|
||||
|
||||
If you plan to use `x.py install` to create an installation, it is recommended
|
||||
that you set the `prefix` value in the `[install]` section to a directory.
|
||||
If you plan to use `x.py install` to create an installation, it is
|
||||
recommended that you set the `prefix` value in the `[install]` section to a
|
||||
directory.
|
||||
|
||||
3. Build and install:
|
||||
|
||||
```sh
|
||||
./x.py build && ./x.py install
|
||||
```
|
||||
```sh
|
||||
./x.py build && ./x.py install
|
||||
```
|
||||
|
||||
When complete, `./x.py install` will place several programs into
|
||||
`$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||
API-documentation tool. If you've set `profile = "user"` or `build.extended = true`, it will
|
||||
also include [Cargo], Rust's package manager.
|
||||
When complete, `./x.py install` will place several programs into
|
||||
`$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||
API-documentation tool. If you've set `profile = "user"` or
|
||||
`build.extended = true`, it will also include [Cargo], Rust's package
|
||||
manager.
|
||||
|
||||
[Cargo]: https://github.com/rust-lang/cargo
|
||||
|
||||
### Building on Windows
|
||||
|
||||
On Windows, we suggest using [winget] to install dependencies by running the following in a terminal:
|
||||
On Windows, we suggest using [winget] to install dependencies by running the
|
||||
following in a terminal:
|
||||
|
||||
```powershell
|
||||
winget install -e Python.Python.3
|
||||
|
|
@ -121,17 +132,19 @@ winget install -e Kitware.CMake
|
|||
winget install -e Git.Git
|
||||
```
|
||||
|
||||
Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`. See
|
||||
[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html) from the
|
||||
Java documentation.
|
||||
Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`.
|
||||
See
|
||||
[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html)
|
||||
from the Java documentation.
|
||||
|
||||
[winget]: https://github.com/microsoft/winget-cli
|
||||
|
||||
There are two prominent ABIs in use on Windows: the native (MSVC) ABI used by
|
||||
Visual Studio and the GNU ABI used by the GCC toolchain. Which version of Rust
|
||||
you need depends largely on what C/C++ libraries you want to interoperate with.
|
||||
Use the MSVC build of Rust to interop with software produced by Visual Studio and
|
||||
the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain.
|
||||
Use the MSVC build of Rust to interop with software produced by Visual Studio
|
||||
and the GNU build to interop with GNU software built using the MinGW/MSYS2
|
||||
toolchain.
|
||||
|
||||
#### MinGW
|
||||
|
||||
|
|
@ -144,7 +157,7 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain
|
|||
2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from the MSYS2 installation
|
||||
directory (e.g. `C:\msys64`), depending on whether you want 32-bit or 64-bit
|
||||
Rust. (As of the latest version of MSYS2 you have to run `msys2_shell.cmd
|
||||
-mingw32` or `msys2_shell.cmd -mingw64` from the command line instead)
|
||||
-mingw32` or `msys2_shell.cmd -mingw64` from the command line instead.)
|
||||
|
||||
3. From this terminal, install the required tools:
|
||||
|
||||
|
|
@ -153,11 +166,11 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain
|
|||
pacman -Sy pacman-mirrors
|
||||
|
||||
# Install build tools needed for Rust. If you're building a 32-bit compiler,
|
||||
# then replace "x86_64" below with "i686". If you've already got git, python,
|
||||
# or CMake installed and in PATH you can remove them from this list. Note
|
||||
# that it is important that you do **not** use the 'python2', 'cmake' and 'ninja'
|
||||
# packages from the 'msys2' subsystem. The build has historically been known
|
||||
# to fail with these packages.
|
||||
# then replace "x86_64" below with "i686". If you've already got Git, Python,
|
||||
# or CMake installed and in PATH you can remove them from this list.
|
||||
# Note that it is important that you do **not** use the 'python2', 'cmake',
|
||||
# and 'ninja' packages from the 'msys2' subsystem.
|
||||
# The build has historically been known to fail with these packages.
|
||||
pacman -S git \
|
||||
make \
|
||||
diffutils \
|
||||
|
|
@ -178,12 +191,12 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain
|
|||
|
||||
MSVC builds of Rust additionally require an installation of Visual Studio 2017
|
||||
(or later) so `rustc` can use its linker. The simplest way is to get
|
||||
[Visual Studio], check the “C++ build tools” and “Windows 10 SDK” workload.
|
||||
[Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload.
|
||||
|
||||
[Visual Studio]: https://visualstudio.microsoft.com/downloads/
|
||||
|
||||
(If you're installing cmake yourself, be careful that “C++ CMake tools for
|
||||
Windows” doesn't get included under “Individual components”.)
|
||||
(If you're installing CMake yourself, be careful that "C++ CMake tools for
|
||||
Windows" doesn't get included under "Individual components".)
|
||||
|
||||
With these dependencies installed, you can build the compiler in a `cmd.exe`
|
||||
shell with:
|
||||
|
|
@ -192,10 +205,11 @@ shell with:
|
|||
python x.py build
|
||||
```
|
||||
|
||||
Right now, building Rust only works with some known versions of Visual Studio. If
|
||||
you have a more recent version installed and the build system doesn't understand,
|
||||
you may need to force rustbuild to use an older version. This can be done
|
||||
by manually calling the appropriate vcvars file before running the bootstrap.
|
||||
Right now, building Rust only works with some known versions of Visual Studio.
|
||||
If you have a more recent version installed and the build system doesn't
|
||||
understand, you may need to force rustbuild to use an older version.
|
||||
This can be done by manually calling the appropriate vcvars file before running
|
||||
the bootstrap.
|
||||
|
||||
```batch
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
|
|
@ -215,9 +229,9 @@ Windows build triples are:
|
|||
- `x86_64-pc-windows-msvc`
|
||||
|
||||
The build triple can be specified by either specifying `--build=<triple>` when
|
||||
invoking `x.py` commands, or by creating a `config.toml` file (as described
|
||||
in [Installing From Source](#installing-from-source)), and modifying the
|
||||
`build` option under the `[build]` section.
|
||||
invoking `x.py` commands, or by creating a `config.toml` file (as described in
|
||||
[Installing from Source](#installing-from-source)), and modifying the `build`
|
||||
option under the `[build]` section.
|
||||
|
||||
### Configure and Make
|
||||
|
||||
|
|
@ -229,33 +243,35 @@ configure script and makefile (the latter of which just invokes `x.py`).
|
|||
make && sudo make install
|
||||
```
|
||||
|
||||
`configure` generates a `config.toml` which can also be used with normal `x.py` invocations.
|
||||
`configure` generates a `config.toml` which can also be used with normal `x.py`
|
||||
invocations.
|
||||
|
||||
## Building Documentation
|
||||
|
||||
If you’d like to build the documentation, it’s almost the same:
|
||||
If you'd like to build the documentation, it's almost the same:
|
||||
|
||||
```sh
|
||||
./x.py doc
|
||||
```
|
||||
|
||||
The generated documentation will appear under `doc` in the `build` directory for
|
||||
the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will be
|
||||
`build\x86_64-pc-windows-msvc\doc`.
|
||||
the ABI used. That is, if the ABI was `x86_64-pc-windows-msvc`, the directory
|
||||
will be `build\x86_64-pc-windows-msvc\doc`.
|
||||
|
||||
## Notes
|
||||
|
||||
Since the Rust compiler is written in Rust, it must be built by a
|
||||
precompiled "snapshot" version of itself (made in an earlier stage of
|
||||
development). As such, source builds require an Internet connection to
|
||||
fetch snapshots, and an OS that can execute the available snapshot binaries.
|
||||
Since the Rust compiler is written in Rust, it must be built by a precompiled
|
||||
"snapshot" version of itself (made in an earlier stage of development).
|
||||
As such, source builds require an Internet connection to fetch snapshots, and an
|
||||
OS that can execute the available snapshot binaries.
|
||||
|
||||
See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of supported platforms.
|
||||
Only "host tools" platforms have a pre-compiled snapshot binary available; to compile for a platform
|
||||
without host tools you must cross-compile.
|
||||
See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of
|
||||
supported platforms.
|
||||
Only "host tools" platforms have a pre-compiled snapshot binary available; to
|
||||
compile for a platform without host tools you must cross-compile.
|
||||
|
||||
You may find that other platforms work, but these are our officially
|
||||
supported build environments that are most likely to work.
|
||||
You may find that other platforms work, but these are our officially supported
|
||||
build environments that are most likely to work.
|
||||
|
||||
## Getting Help
|
||||
|
||||
|
|
@ -267,9 +283,9 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|||
|
||||
## License
|
||||
|
||||
Rust is primarily distributed under the terms of both the MIT license
|
||||
and the Apache License (Version 2.0), with portions covered by various
|
||||
BSD-like licenses.
|
||||
Rust is primarily distributed under the terms of both the MIT license and the
|
||||
Apache License (Version 2.0), with portions covered by various BSD-like
|
||||
licenses.
|
||||
|
||||
See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and
|
||||
[COPYRIGHT](COPYRIGHT) for details.
|
||||
|
|
@ -277,13 +293,14 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and
|
|||
## Trademark
|
||||
|
||||
[The Rust Foundation][rust-foundation] owns and protects the Rust and Cargo
|
||||
trademarks and logos (the “Rust Trademarks”).
|
||||
trademarks and logos (the "Rust Trademarks").
|
||||
|
||||
If you want to use these names or brands, please read the [media guide][media-guide].
|
||||
If you want to use these names or brands, please read the
|
||||
[media guide][media-guide].
|
||||
|
||||
Third-party logos may be subject to third-party copyrights and trademarks. See
|
||||
[Licenses][policies-licenses] for details.
|
||||
|
||||
[rust-foundation]: https://foundation.rust-lang.org/
|
||||
[media-guide]: https://www.rust-lang.org/policies/media-guide
|
||||
[media-guide]: https://foundation.rust-lang.org/policies/logo-policy-and-media-guide/
|
||||
[policies-licenses]: https://www.rust-lang.org/policies/licenses
|
||||
|
|
|
|||
|
|
@ -2032,7 +2032,8 @@ impl Clone for Ty {
|
|||
impl Ty {
|
||||
pub fn peel_refs(&self) -> &Self {
|
||||
let mut final_ty = self;
|
||||
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
|
||||
while let TyKind::Ref(_, MutTy { ty, .. }) | TyKind::Ptr(MutTy { ty, .. }) = &final_ty.kind
|
||||
{
|
||||
final_ty = ty;
|
||||
}
|
||||
final_ty
|
||||
|
|
|
|||
|
|
@ -1100,16 +1100,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
extern_block_suggestion: match sig.header.ext {
|
||||
Extern::None => None,
|
||||
Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
|
||||
Extern::Implicit(start_span) => Some(ExternBlockSuggestion::Implicit {
|
||||
start_span,
|
||||
end_span: item.span.shrink_to_hi(),
|
||||
abi: None,
|
||||
}),
|
||||
Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
|
||||
start_span,
|
||||
end_span: item.span.shrink_to_hi(),
|
||||
abi: Some(abi.symbol_unescaped),
|
||||
}),
|
||||
Extern::Explicit(abi, start_span) => {
|
||||
Some(ExternBlockSuggestion::Explicit {
|
||||
start_span,
|
||||
end_span: item.span.shrink_to_hi(),
|
||||
abi: abi.symbol_unescaped,
|
||||
})
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
|
|
@ -207,28 +206,21 @@ pub struct FnWithoutBody {
|
|||
pub extern_block_suggestion: Option<ExternBlockSuggestion>,
|
||||
}
|
||||
|
||||
pub struct ExternBlockSuggestion {
|
||||
pub start_span: Span,
|
||||
pub end_span: Span,
|
||||
pub abi: Option<Symbol>,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for ExternBlockSuggestion {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
let start_suggestion = if let Some(abi) = self.abi {
|
||||
format!("extern \"{}\" {{", abi)
|
||||
} else {
|
||||
"extern {".to_owned()
|
||||
};
|
||||
let end_suggestion = " }".to_owned();
|
||||
|
||||
diag.multipart_suggestion(
|
||||
fluent::extern_block_suggestion,
|
||||
vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ExternBlockSuggestion {
|
||||
#[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")]
|
||||
Implicit {
|
||||
#[suggestion_part(code = "extern {{")]
|
||||
start_span: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
end_span: Span,
|
||||
},
|
||||
#[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")]
|
||||
Explicit {
|
||||
#[suggestion_part(code = "extern \"{abi}\" {{")]
|
||||
start_span: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
end_span: Span,
|
||||
abi: Symbol,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -673,40 +673,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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::EarlyBinder<
|
||||
&[(ty::Predicate<'tcx>, Span)],
|
||||
>,
|
||||
substs| {
|
||||
predicates.0.iter().find_map(|(pred, _)| {
|
||||
let pred = if let Some(substs) = substs {
|
||||
predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
|
||||
} else {
|
||||
pred.kind().skip_binder()
|
||||
};
|
||||
if let ty::PredicateKind::Clause(ty::Clause::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);
|
||||
}
|
||||
let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
|
||||
&& 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
|
||||
})
|
||||
}
|
||||
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.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
|
||||
.map_bound(|p| p.predicates),
|
||||
None,
|
||||
),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
|
||||
}
|
||||
let borrow_level = match *ty.kind() {
|
||||
ty::Param(_) => tcx
|
||||
.explicit_predicates_of(self.mir_def_id().to_def_id())
|
||||
.predicates
|
||||
.iter()
|
||||
.copied()
|
||||
.find_map(find_fn_kind_from_did),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
|
||||
.bound_explicit_item_bounds(def_id)
|
||||
.subst_iter_copied(tcx, substs)
|
||||
.find_map(find_fn_kind_from_did),
|
||||
ty::Closure(_, substs) => match substs.as_closure().kind() {
|
||||
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
|
||||
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
|
||||
|
|
@ -2199,7 +2193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let mut back_edge_stack = Vec::new();
|
||||
|
||||
predecessor_locations(self.body, location).for_each(|predecessor| {
|
||||
if location.dominates(predecessor, &self.dominators) {
|
||||
if location.dominates(predecessor, self.dominators()) {
|
||||
back_edge_stack.push(predecessor)
|
||||
} else {
|
||||
stack.push(predecessor);
|
||||
|
|
@ -2311,7 +2305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
let mut has_predecessor = false;
|
||||
predecessor_locations(self.body, location).for_each(|predecessor| {
|
||||
if location.dominates(predecessor, &self.dominators) {
|
||||
if location.dominates(predecessor, self.dominators()) {
|
||||
back_edge_stack.push(predecessor)
|
||||
} else {
|
||||
stack.push(predecessor);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,13 @@
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res::Def;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::GenericBound::Trait;
|
||||
use rustc_hir::QPath::Resolved;
|
||||
use rustc_hir::WherePredicate::BoundPredicate;
|
||||
use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
|
||||
use rustc_infer::infer::{
|
||||
error_reporting::nice_region_error::{
|
||||
self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
|
||||
|
|
@ -186,6 +191,101 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
|
||||
// For generic associated types (GATs) which implied 'static requirement
|
||||
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
|
||||
// and the span which bounded to the trait for adding 'static lifetime suggestion
|
||||
fn suggest_static_lifetime_for_gat_from_hrtb(
|
||||
&self,
|
||||
diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
lower_bound: RegionVid,
|
||||
) {
|
||||
let mut suggestions = vec![];
|
||||
let hir = self.infcx.tcx.hir();
|
||||
|
||||
// find generic associated types in the given region 'lower_bound'
|
||||
let gat_id_and_generics = self
|
||||
.regioncx
|
||||
.placeholders_contained_in(lower_bound)
|
||||
.map(|placeholder| {
|
||||
if let Some(id) = placeholder.name.get_id()
|
||||
&& let Some(placeholder_id) = id.as_local()
|
||||
&& let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id)
|
||||
&& let Some(generics_impl) = hir.get_parent(gat_hir_id).generics()
|
||||
{
|
||||
Some((gat_hir_id, generics_impl))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
debug!(?gat_id_and_generics);
|
||||
|
||||
// find higher-ranked trait bounds bounded to the generic associated types
|
||||
let mut hrtb_bounds = vec![];
|
||||
gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
|
||||
for pred in generics.predicates {
|
||||
let BoundPredicate(
|
||||
WhereBoundPredicate {
|
||||
bound_generic_params,
|
||||
bounds,
|
||||
..
|
||||
}) = pred else { continue; };
|
||||
if bound_generic_params
|
||||
.iter()
|
||||
.rfind(|bgp| hir.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
|
||||
.is_some()
|
||||
{
|
||||
for bound in *bounds {
|
||||
hrtb_bounds.push(bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
debug!(?hrtb_bounds);
|
||||
|
||||
hrtb_bounds.iter().for_each(|bound| {
|
||||
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
|
||||
diag.span_note(
|
||||
*trait_span,
|
||||
format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")
|
||||
);
|
||||
let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; };
|
||||
let Def(_, trait_res_defid) = trait_ref.path.res else { return; };
|
||||
debug!(?generics_fn);
|
||||
generics_fn.predicates.iter().for_each(|predicate| {
|
||||
let BoundPredicate(
|
||||
WhereBoundPredicate {
|
||||
span: bounded_span,
|
||||
bounded_ty,
|
||||
bounds,
|
||||
..
|
||||
}
|
||||
) = predicate else { return; };
|
||||
bounds.iter().for_each(|bd| {
|
||||
if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd
|
||||
&& let Def(_, res_defid) = tr_ref.path.res
|
||||
&& res_defid == trait_res_defid // trait id matches
|
||||
&& let TyKind::Path(Resolved(_, path)) = bounded_ty.kind
|
||||
&& let Def(_, defid) = path.res
|
||||
&& generics_fn.params
|
||||
.iter()
|
||||
.rfind(|param| param.def_id.to_def_id() == defid)
|
||||
.is_some() {
|
||||
suggestions.push((bounded_span.shrink_to_hi(), format!(" + 'static")));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
if suggestions.len() > 0 {
|
||||
suggestions.dedup();
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("consider restricting the type parameter to the `'static` lifetime"),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
|
||||
pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
|
||||
// Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
|
||||
|
|
@ -223,12 +323,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// to report it; we could probably handle it by
|
||||
// iterating over the universal regions and reporting
|
||||
// an error that multiple bounds are required.
|
||||
self.buffer_error(self.infcx.tcx.sess.create_err(
|
||||
GenericDoesNotLiveLongEnough {
|
||||
let mut diag =
|
||||
self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough {
|
||||
kind: type_test.generic_kind.to_string(),
|
||||
span: type_test_span,
|
||||
},
|
||||
));
|
||||
});
|
||||
|
||||
// Add notes and suggestions for the case of 'static lifetime
|
||||
// implied but not specified when a generic associated types
|
||||
// are from higher-ranked trait bounds
|
||||
self.suggest_static_lifetime_for_gat_from_hrtb(
|
||||
&mut diag,
|
||||
type_test.lower_bound,
|
||||
);
|
||||
|
||||
self.buffer_error(diag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(trusted_step)]
|
||||
|
|
@ -39,6 +40,7 @@ use rustc_span::{Span, Symbol};
|
|||
|
||||
use either::Either;
|
||||
use smallvec::SmallVec;
|
||||
use std::cell::OnceCell;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -333,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
used_mut: Default::default(),
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
borrow_set: Rc::clone(&borrow_set),
|
||||
dominators: Dominators::dummy(), // not used
|
||||
dominators: Default::default(),
|
||||
upvars: Vec::new(),
|
||||
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
|
||||
region_names: RefCell::default(),
|
||||
|
|
@ -346,8 +348,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
};
|
||||
}
|
||||
|
||||
let dominators = body.basic_blocks.dominators();
|
||||
|
||||
let mut mbcx = MirBorrowckCtxt {
|
||||
infcx,
|
||||
param_env,
|
||||
|
|
@ -364,7 +364,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
used_mut: Default::default(),
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
borrow_set: Rc::clone(&borrow_set),
|
||||
dominators,
|
||||
dominators: Default::default(),
|
||||
upvars,
|
||||
local_names,
|
||||
region_names: RefCell::default(),
|
||||
|
|
@ -534,7 +534,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
|
|||
borrow_set: Rc<BorrowSet<'tcx>>,
|
||||
|
||||
/// Dominators for MIR
|
||||
dominators: Dominators<BasicBlock>,
|
||||
dominators: OnceCell<Dominators<BasicBlock>>,
|
||||
|
||||
/// Information about upvars not necessarily preserved in types or MIR
|
||||
upvars: Vec<Upvar<'tcx>>,
|
||||
|
|
@ -1051,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
(Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
|
||||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(&this.dominators, borrow, location) {
|
||||
if !is_active(this.dominators(), borrow, location) {
|
||||
assert!(allow_two_phase_borrow(borrow.kind));
|
||||
return Control::Continue;
|
||||
}
|
||||
|
|
@ -2219,6 +2219,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
|
||||
path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
|
||||
}
|
||||
|
||||
fn dominators(&self) -> &Dominators<BasicBlock> {
|
||||
self.dominators.get_or_init(|| self.body.basic_blocks.dominators())
|
||||
}
|
||||
}
|
||||
|
||||
mod error {
|
||||
|
|
|
|||
|
|
@ -527,6 +527,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
self.scc_values.region_value_str(scc)
|
||||
}
|
||||
|
||||
pub(crate) fn placeholders_contained_in<'a>(
|
||||
&'a self,
|
||||
r: RegionVid,
|
||||
) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
self.scc_values.placeholders_contained_in(scc)
|
||||
}
|
||||
|
||||
/// Returns access to the value of `r` for debugging purposes.
|
||||
pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ use rustc_span::Span;
|
|||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
||||
use crate::session_diagnostics::NonGenericOpaqueTypeParam;
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
|
@ -250,7 +252,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
let definition_ty = instantiated_ty
|
||||
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
|
||||
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
|
||||
.ty;
|
||||
|
||||
if !check_opaque_type_parameter_valid(
|
||||
|
|
@ -389,17 +391,13 @@ fn check_opaque_type_parameter_valid(
|
|||
} else {
|
||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||
let opaque_param = opaque_generics.param_at(i, tcx);
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(
|
||||
tcx.def_span(opaque_param.def_id),
|
||||
&format!(
|
||||
"used non-generic {} `{}` for generic parameter",
|
||||
opaque_param.kind.descr(),
|
||||
arg,
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
let kind = opaque_param.kind.descr();
|
||||
tcx.sess.emit_err(NonGenericOpaqueTypeParam {
|
||||
ty: arg,
|
||||
kind,
|
||||
span,
|
||||
param_span: tcx.def_span(opaque_param.def_id),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_errors::{IntoDiagnosticArg, MultiSpan};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{GenericArg, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::diagnostics::RegionName;
|
||||
|
|
@ -240,3 +240,14 @@ pub(crate) struct MoveBorrow<'a> {
|
|||
#[label]
|
||||
pub borrow_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")]
|
||||
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
|
||||
pub ty: GenericArg<'tcx>,
|
||||
pub kind: &'a str,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub param_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,11 +107,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
|
||||
locations: Locations,
|
||||
) {
|
||||
for (predicate, span) in instantiated_predicates
|
||||
.predicates
|
||||
.into_iter()
|
||||
.zip(instantiated_predicates.spans.into_iter())
|
||||
{
|
||||
for (predicate, span) in instantiated_predicates {
|
||||
debug!(?predicate);
|
||||
let category = ConstraintCategory::Predicate(span);
|
||||
let predicate = self.normalize_with_category(predicate, locations, category);
|
||||
|
|
|
|||
|
|
@ -359,14 +359,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
|
||||
}
|
||||
|
||||
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
|
||||
OutlivesBound::RegionSubAlias(r_a, alias_b) => {
|
||||
self.region_bound_pairs
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
|
||||
}
|
||||
|
||||
OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
|
||||
self.region_bound_pairs
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ pub fn expand_deriving_clone(
|
|||
nonself_args: Vec::new(),
|
||||
ret_ty: Self_,
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: false,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: substructure,
|
||||
}],
|
||||
associated_types: Vec::new(),
|
||||
|
|
@ -177,7 +177,9 @@ fn cs_clone(
|
|||
all_fields = af;
|
||||
vdata = &variant.data;
|
||||
}
|
||||
EnumTag(..) => cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)),
|
||||
EnumTag(..) | AllFieldlessEnum(..) => {
|
||||
cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,))
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => {
|
||||
cx.span_bug(trait_span, &format!("associated function in `derive({})`", name))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ pub fn expand_deriving_eq(
|
|||
nonself_args: vec![],
|
||||
ret_ty: Unit,
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: true,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
cs_total_eq_assert(a, b, c)
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ pub fn expand_deriving_ord(
|
|||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty: Path(path_std!(cmp::Ordering)),
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: true,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
|
||||
}],
|
||||
associated_types: Vec::new(),
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ pub fn expand_deriving_partial_eq(
|
|||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty: Path(path_local!(bool)),
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: true,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
|
||||
}];
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub fn expand_deriving_partial_ord(
|
|||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty,
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: true,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
|
||||
cs_partial_cmp(cx, span, substr)
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::deriving::generic::ty::*;
|
|||
use crate::deriving::generic::*;
|
||||
use crate::deriving::path_std;
|
||||
|
||||
use ast::EnumDef;
|
||||
use rustc_ast::{self as ast, MetaItem};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
|
|
@ -31,7 +32,8 @@ pub fn expand_deriving_debug(
|
|||
nonself_args: vec![(fmtr, sym::f)],
|
||||
ret_ty: Path(path_std!(fmt::Result)),
|
||||
attributes: ast::AttrVec::new(),
|
||||
unify_fieldless_variants: false,
|
||||
fieldless_variants_strategy:
|
||||
FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
show_substructure(a, b, c)
|
||||
})),
|
||||
|
|
@ -43,16 +45,18 @@ pub fn expand_deriving_debug(
|
|||
}
|
||||
|
||||
fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||
// We want to make sure we have the ctxt set so that we can use unstable methods
|
||||
let span = cx.with_def_site_ctxt(span);
|
||||
|
||||
let (ident, vdata, fields) = match substr.fields {
|
||||
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
|
||||
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
|
||||
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
|
||||
EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
|
||||
cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
|
||||
}
|
||||
};
|
||||
|
||||
// We want to make sure we have the ctxt set so that we can use unstable methods
|
||||
let span = cx.with_def_site_ctxt(span);
|
||||
let name = cx.expr_str(span, ident.name);
|
||||
let fmt = substr.nonselflike_args[0].clone();
|
||||
|
||||
|
|
@ -173,3 +177,47 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
|||
BlockOrExpr::new_mixed(stmts, Some(expr))
|
||||
}
|
||||
}
|
||||
|
||||
/// Special case for enums with no fields. Builds:
|
||||
/// ```text
|
||||
/// impl ::core::fmt::Debug for A {
|
||||
/// fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
/// ::core::fmt::Formatter::write_str(f,
|
||||
/// match self {
|
||||
/// A::A => "A",
|
||||
/// A::B() => "B",
|
||||
/// A::C {} => "C",
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn show_fieldless_enum(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
def: &EnumDef,
|
||||
substr: &Substructure<'_>,
|
||||
) -> BlockOrExpr {
|
||||
let fmt = substr.nonselflike_args[0].clone();
|
||||
let arms = def
|
||||
.variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let variant_path = cx.path(span, vec![substr.type_ident, v.ident]);
|
||||
let pat = match &v.data {
|
||||
ast::VariantData::Tuple(fields, _) => {
|
||||
debug_assert!(fields.is_empty());
|
||||
cx.pat_tuple_struct(span, variant_path, vec![])
|
||||
}
|
||||
ast::VariantData::Struct(fields, _) => {
|
||||
debug_assert!(fields.is_empty());
|
||||
cx.pat_struct(span, variant_path, vec![])
|
||||
}
|
||||
ast::VariantData::Unit(_) => cx.pat_path(span, variant_path),
|
||||
};
|
||||
cx.arm(span, pat, cx.expr_str(span, v.ident.name))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let name = cx.expr_match(span, cx.expr_self(span), arms);
|
||||
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
|
||||
BlockOrExpr::new_expr(cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub fn expand_deriving_rustc_decodable(
|
|||
PathKind::Std,
|
||||
)),
|
||||
attributes: ast::AttrVec::new(),
|
||||
unify_fieldless_variants: false,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
decodable_substructure(a, b, c, krate)
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub fn expand_deriving_default(
|
|||
nonself_args: Vec::new(),
|
||||
ret_ty: Self_,
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: false,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
|
||||
match substr.fields {
|
||||
StaticStruct(_, fields) => {
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ pub fn expand_deriving_rustc_encodable(
|
|||
PathKind::Std,
|
||||
)),
|
||||
attributes: AttrVec::new(),
|
||||
unify_fieldless_variants: false,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
encodable_substructure(a, b, c, krate)
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -222,14 +222,27 @@ pub struct MethodDef<'a> {
|
|||
|
||||
pub attributes: ast::AttrVec,
|
||||
|
||||
/// Can we combine fieldless variants for enums into a single match arm?
|
||||
/// If true, indicates that the trait operation uses the enum tag in some
|
||||
/// way.
|
||||
pub unify_fieldless_variants: bool,
|
||||
pub fieldless_variants_strategy: FieldlessVariantsStrategy,
|
||||
|
||||
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
|
||||
}
|
||||
|
||||
/// How to handle fieldless enum variants.
|
||||
#[derive(PartialEq)]
|
||||
pub enum FieldlessVariantsStrategy {
|
||||
/// Combine fieldless variants into a single match arm.
|
||||
/// This assumes that relevant information has been handled
|
||||
/// by looking at the enum's discriminant.
|
||||
Unify,
|
||||
/// Don't do anything special about fieldless variants. They are
|
||||
/// handled like any other variant.
|
||||
Default,
|
||||
/// If all variants of the enum are fieldless, expand the special
|
||||
/// `AllFieldLessEnum` substructure, so that the entire enum can be handled
|
||||
/// at once.
|
||||
SpecializeIfAllVariantsFieldless,
|
||||
}
|
||||
|
||||
/// All the data about the data structure/method being derived upon.
|
||||
pub struct Substructure<'a> {
|
||||
/// ident of self
|
||||
|
|
@ -264,9 +277,14 @@ pub enum StaticFields {
|
|||
|
||||
/// A summary of the possible sets of fields.
|
||||
pub enum SubstructureFields<'a> {
|
||||
/// A non-static method with `Self` is a struct.
|
||||
/// A non-static method where `Self` is a struct.
|
||||
Struct(&'a ast::VariantData, Vec<FieldInfo>),
|
||||
|
||||
/// A non-static method handling the entire enum at once
|
||||
/// (after it has been determined that none of the enum
|
||||
/// variants has any fields).
|
||||
AllFieldlessEnum(&'a ast::EnumDef),
|
||||
|
||||
/// Matching variants of the enum: variant index, variant count, ast::Variant,
|
||||
/// fields: the field name is only non-`None` in the case of a struct
|
||||
/// variant.
|
||||
|
|
@ -1086,8 +1104,8 @@ impl<'a> MethodDef<'a> {
|
|||
/// ```
|
||||
/// Creates a tag check combined with a match for a tuple of all
|
||||
/// `selflike_args`, with an arm for each variant with fields, possibly an
|
||||
/// arm for each fieldless variant (if `!unify_fieldless_variants` is not
|
||||
/// true), and possibly a default arm.
|
||||
/// arm for each fieldless variant (if `unify_fieldless_variants` is not
|
||||
/// `Unify`), and possibly a default arm.
|
||||
fn expand_enum_method_body<'b>(
|
||||
&self,
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
|
|
@ -1101,7 +1119,8 @@ impl<'a> MethodDef<'a> {
|
|||
let variants = &enum_def.variants;
|
||||
|
||||
// Traits that unify fieldless variants always use the tag(s).
|
||||
let uses_tags = self.unify_fieldless_variants;
|
||||
let unify_fieldless_variants =
|
||||
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
|
||||
|
||||
// There is no sensible code to be generated for *any* deriving on a
|
||||
// zero-variant enum. So we just generate a failing expression.
|
||||
|
|
@ -1161,23 +1180,35 @@ impl<'a> MethodDef<'a> {
|
|||
// match is necessary.
|
||||
let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty());
|
||||
if all_fieldless {
|
||||
if uses_tags && variants.len() > 1 {
|
||||
// If the type is fieldless and the trait uses the tag and
|
||||
// there are multiple variants, we need just an operation on
|
||||
// the tag(s).
|
||||
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
||||
let mut tag_check = self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&EnumTag(tag_field, None),
|
||||
);
|
||||
tag_let_stmts.append(&mut tag_check.0);
|
||||
return BlockOrExpr(tag_let_stmts, tag_check.1);
|
||||
}
|
||||
|
||||
if variants.len() == 1 {
|
||||
if variants.len() > 1 {
|
||||
match self.fieldless_variants_strategy {
|
||||
FieldlessVariantsStrategy::Unify => {
|
||||
// If the type is fieldless and the trait uses the tag and
|
||||
// there are multiple variants, we need just an operation on
|
||||
// the tag(s).
|
||||
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
||||
let mut tag_check = self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&EnumTag(tag_field, None),
|
||||
);
|
||||
tag_let_stmts.append(&mut tag_check.0);
|
||||
return BlockOrExpr(tag_let_stmts, tag_check.1);
|
||||
}
|
||||
FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
|
||||
return self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&AllFieldlessEnum(enum_def),
|
||||
);
|
||||
}
|
||||
FieldlessVariantsStrategy::Default => (),
|
||||
}
|
||||
} else if variants.len() == 1 {
|
||||
// If there is a single variant, we don't need an operation on
|
||||
// the tag(s). Just use the most degenerate result.
|
||||
return self.call_substructure_method(
|
||||
|
|
@ -1187,7 +1218,7 @@ impl<'a> MethodDef<'a> {
|
|||
nonselflike_args,
|
||||
&EnumMatching(0, 1, &variants[0], Vec::new()),
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// These arms are of the form:
|
||||
|
|
@ -1198,7 +1229,7 @@ impl<'a> MethodDef<'a> {
|
|||
let mut match_arms: Vec<ast::Arm> = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty()))
|
||||
.filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty()))
|
||||
.map(|(index, variant)| {
|
||||
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
|
||||
// (see "Final wrinkle" note below for why.)
|
||||
|
|
@ -1249,7 +1280,7 @@ impl<'a> MethodDef<'a> {
|
|||
// Add a default arm to the match, if necessary.
|
||||
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
|
||||
let default = match first_fieldless {
|
||||
Some(v) if self.unify_fieldless_variants => {
|
||||
Some(v) if unify_fieldless_variants => {
|
||||
// We need a default case that handles all the fieldless
|
||||
// variants. The index and actual variant aren't meaningful in
|
||||
// this case, so just use dummy values.
|
||||
|
|
@ -1296,7 +1327,7 @@ impl<'a> MethodDef<'a> {
|
|||
// If the trait uses the tag and there are multiple variants, we need
|
||||
// to add a tag check operation before the match. Otherwise, the match
|
||||
// is enough.
|
||||
if uses_tags && variants.len() > 1 {
|
||||
if unify_fieldless_variants && variants.len() > 1 {
|
||||
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
||||
|
||||
// Combine a tag check with the match.
|
||||
|
|
@ -1580,5 +1611,6 @@ where
|
|||
}
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
||||
AllFieldlessEnum(..) => cx.span_bug(trait_span, "fieldless enum in `derive`"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub fn expand_deriving_hash(
|
|||
nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
|
||||
ret_ty: Unit,
|
||||
attributes: AttrVec::new(),
|
||||
unify_fieldless_variants: true,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
hash_substructure(a, b, c)
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl DebugContext {
|
|||
.working_dir
|
||||
.to_string_lossy(FileNameDisplayPreference::Remapped)
|
||||
.into_owned();
|
||||
let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
|
||||
let (name, file_info) = match tcx.sess.local_crate_source_file() {
|
||||
Some(path) => {
|
||||
let name = path.to_string_lossy().into_owned();
|
||||
(name, None)
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
layout: TyAndLayout<'tcx>,
|
||||
offset: Size,
|
||||
) {
|
||||
if !scalar.is_always_valid(bx) {
|
||||
if !scalar.is_uninit_valid() {
|
||||
bx.noundef_metadata(load);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
|
|||
use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefIdSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_llvm::RustString;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
|
|
@ -291,7 +291,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
|
|||
|
||||
let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics();
|
||||
|
||||
let eligible_def_ids: DefIdSet = tcx
|
||||
let eligible_def_ids: Vec<DefId> = tcx
|
||||
.mir_keys(())
|
||||
.iter()
|
||||
.filter_map(|local_def_id| {
|
||||
|
|
@ -317,7 +317,9 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
|
|||
|
||||
let codegenned_def_ids = tcx.codegened_and_inlined_items(());
|
||||
|
||||
for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) {
|
||||
for non_codegenned_def_id in
|
||||
eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id))
|
||||
{
|
||||
let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
|
||||
|
||||
// If a function is marked `#[no_coverage]`, then skip generating a
|
||||
|
|
|
|||
|
|
@ -782,10 +782,10 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
codegen_unit_name: &str,
|
||||
debug_context: &CodegenUnitDebugContext<'ll, 'tcx>,
|
||||
) -> &'ll DIDescriptor {
|
||||
let mut name_in_debuginfo = match tcx.sess.local_crate_source_file {
|
||||
Some(ref path) => path.clone(),
|
||||
None => PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()),
|
||||
};
|
||||
let mut name_in_debuginfo = tcx
|
||||
.sess
|
||||
.local_crate_source_file()
|
||||
.unwrap_or_else(|| PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()));
|
||||
|
||||
// To avoid breaking split DWARF, we need to ensure that each codegen unit
|
||||
// has a unique `DW_AT_name`. This is because there's a remote chance that
|
||||
|
|
|
|||
|
|
@ -173,11 +173,15 @@ fn exported_symbols_provider_local(
|
|||
return &[];
|
||||
}
|
||||
|
||||
let mut symbols: Vec<_> = tcx
|
||||
.reachable_non_generics(LOCAL_CRATE)
|
||||
.iter()
|
||||
.map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
|
||||
.collect();
|
||||
// FIXME: Sorting this is unnecessary since we are sorting later anyway.
|
||||
// Can we skip the later sorting?
|
||||
let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| {
|
||||
tcx.reachable_non_generics(LOCAL_CRATE)
|
||||
.to_sorted(&hcx, true)
|
||||
.into_iter()
|
||||
.map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
|
||||
.collect()
|
||||
});
|
||||
|
||||
if tcx.entry_fn(()).is_some() {
|
||||
let exported_symbol =
|
||||
|
|
|
|||
|
|
@ -964,16 +964,19 @@ pub fn provide(providers: &mut Providers) {
|
|||
};
|
||||
|
||||
let (defids, _) = tcx.collect_and_partition_mono_items(cratenum);
|
||||
for id in &*defids {
|
||||
|
||||
let any_for_speed = defids.items().any(|id| {
|
||||
let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
|
||||
match optimize {
|
||||
attr::OptimizeAttr::None => continue,
|
||||
attr::OptimizeAttr::Size => continue,
|
||||
attr::OptimizeAttr::Speed => {
|
||||
return for_speed;
|
||||
}
|
||||
attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
|
||||
attr::OptimizeAttr::Speed => true,
|
||||
}
|
||||
});
|
||||
|
||||
if any_for_speed {
|
||||
return for_speed;
|
||||
}
|
||||
|
||||
tcx.sess.opts.optimize
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,16 +36,16 @@ impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
|
|||
impl fmt::Display for ConstEvalErrKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use self::ConstEvalErrKind::*;
|
||||
match *self {
|
||||
match self {
|
||||
ConstAccessesStatic => write!(f, "constant accesses static"),
|
||||
ModifiedGlobal => {
|
||||
write!(f, "modifying a static's initial value from another static's initializer")
|
||||
}
|
||||
AssertFailure(ref msg) => write!(f, "{:?}", msg),
|
||||
AssertFailure(msg) => write!(f, "{:?}", msg),
|
||||
Panic { msg, line, col, file } => {
|
||||
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col)
|
||||
}
|
||||
Abort(ref msg) => write!(f, "{}", msg),
|
||||
Abort(msg) => write!(f, "{}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
|||
/// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer
|
||||
/// may not have an address.
|
||||
///
|
||||
/// If `ptr` does have a known address, then we return `CONTINUE` and the function call should
|
||||
/// If `ptr` does have a known address, then we return `Continue(())` and the function call should
|
||||
/// proceed as normal.
|
||||
///
|
||||
/// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most
|
||||
|
|
@ -273,18 +273,18 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
|||
ret,
|
||||
StackPopUnwind::NotAllowed,
|
||||
)?;
|
||||
Ok(ControlFlow::BREAK)
|
||||
Ok(ControlFlow::Break(()))
|
||||
} else {
|
||||
// Not alignable in const, return `usize::MAX`.
|
||||
let usize_max = Scalar::from_machine_usize(self.machine_usize_max(), self);
|
||||
self.write_scalar(usize_max, dest)?;
|
||||
self.return_to_block(ret)?;
|
||||
Ok(ControlFlow::BREAK)
|
||||
Ok(ControlFlow::Break(()))
|
||||
}
|
||||
}
|
||||
Err(_addr) => {
|
||||
// The pointer has an address, continue with function call.
|
||||
Ok(ControlFlow::CONTINUE)
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -533,7 +533,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
let eval_to_int =
|
||||
|op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
|
||||
let err = match msg {
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
BoundsCheck { len, index } => {
|
||||
let len = eval_to_int(len)?;
|
||||
let index = eval_to_int(index)?;
|
||||
BoundsCheck { len, index }
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
|
||||
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
||||
}
|
||||
(_, &ty::Dynamic(ref data, _, ty::Dyn)) => {
|
||||
(_, &ty::Dynamic(data, _, ty::Dyn)) => {
|
||||
// Initial cast from sized to dyn trait
|
||||
let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
|
||||
let ptr = self.read_scalar(src)?;
|
||||
|
|
|
|||
|
|
@ -79,9 +79,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
|||
}
|
||||
sym::variant_count => match tp_ty.kind() {
|
||||
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
|
||||
ty::Adt(ref adt, _) => {
|
||||
ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx)
|
||||
}
|
||||
ty::Adt(adt, _) => ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx),
|
||||
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
|
||||
throw_inval!(TooGeneric)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -863,7 +863,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
|
|||
|
||||
write!(fmt, "{id:?}")?;
|
||||
match self.ecx.memory.alloc_map.get(id) {
|
||||
Some(&(kind, ref alloc)) => {
|
||||
Some((kind, alloc)) => {
|
||||
// normal alloc
|
||||
write!(fmt, " ({}, ", kind)?;
|
||||
write_allocation_track_relocs(
|
||||
|
|
|
|||
|
|
@ -533,11 +533,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
use rustc_middle::mir::Operand::*;
|
||||
let op = match *mir_op {
|
||||
let op = match mir_op {
|
||||
// FIXME: do some more logic on `move` to invalidate the old location
|
||||
Copy(place) | Move(place) => self.eval_place_to_op(place, layout)?,
|
||||
&Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?,
|
||||
|
||||
Constant(ref constant) => {
|
||||
Constant(constant) => {
|
||||
let c =
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
M::retag_place_contents(self, *kind, &dest)?;
|
||||
}
|
||||
|
||||
Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
|
||||
Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
|
||||
|
||||
// Statements we do not track.
|
||||
AscribeUserType(..) => {}
|
||||
|
|
@ -163,8 +163,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.copy_op(&op, &dest, /*allow_transmute*/ false)?;
|
||||
}
|
||||
|
||||
CopyForDeref(ref place) => {
|
||||
let op = self.eval_place_to_op(*place, Some(dest.layout))?;
|
||||
CopyForDeref(place) => {
|
||||
let op = self.eval_place_to_op(place, Some(dest.layout))?;
|
||||
self.copy_op(&op, &dest, /* allow_transmute*/ false)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ where
|
|||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !ty.needs_subst() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
|
|
@ -48,7 +48,7 @@ where
|
|||
return subst.visit_with(self);
|
||||
}
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
)
|
||||
}
|
||||
// Recursive checking
|
||||
if let Some(ref mut ref_tracking) = self.ref_tracking {
|
||||
if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() {
|
||||
// Proceed recursively even for ZST, no reason to skip them!
|
||||
// `!` is a ZST and we want to validate it.
|
||||
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
|
||||
|
|
|
|||
|
|
@ -481,12 +481,12 @@ macro_rules! make_value_visitor {
|
|||
};
|
||||
|
||||
// Visit the fields of this value.
|
||||
match v.layout().fields {
|
||||
match &v.layout().fields {
|
||||
FieldsShape::Primitive => {}
|
||||
FieldsShape::Union(fields) => {
|
||||
&FieldsShape::Union(fields) => {
|
||||
self.visit_union(v, fields)?;
|
||||
}
|
||||
FieldsShape::Arbitrary { ref offsets, .. } => {
|
||||
FieldsShape::Arbitrary { offsets, .. } => {
|
||||
// FIXME: We collect in a vec because otherwise there are lifetime
|
||||
// errors: Projecting to a field needs access to `ecx`.
|
||||
let fields: Vec<InterpResult<'tcx, Self::V>> =
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ Rust MIR: a lowered representation of Rust.
|
|||
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(let_chains)]
|
||||
|
|
|
|||
|
|
@ -442,7 +442,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
self.super_rvalue(rvalue, location);
|
||||
|
||||
match *rvalue {
|
||||
match rvalue {
|
||||
Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess),
|
||||
|
||||
Rvalue::Use(_)
|
||||
|
|
@ -451,18 +451,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::Len(_) => {}
|
||||
|
||||
Rvalue::Aggregate(ref kind, ..) => {
|
||||
if let AggregateKind::Generator(def_id, ..) = kind.as_ref() {
|
||||
if let Some(generator_kind) = self.tcx.generator_kind(def_id.to_def_id()) {
|
||||
if matches!(generator_kind, hir::GeneratorKind::Async(..)) {
|
||||
self.check_op(ops::Generator(generator_kind));
|
||||
}
|
||||
}
|
||||
Rvalue::Aggregate(kind, ..) => {
|
||||
if let AggregateKind::Generator(def_id, ..) = kind.as_ref()
|
||||
&& let Some(generator_kind @ hir::GeneratorKind::Async(..)) = self.tcx.generator_kind(def_id.to_def_id())
|
||||
{
|
||||
self.check_op(ops::Generator(generator_kind));
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place)
|
||||
| Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => {
|
||||
Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => {
|
||||
let ty = place.ty(self.body, self.tcx).ty;
|
||||
let is_allowed = match ty.kind() {
|
||||
// Inside a `static mut`, `&mut [...]` is allowed.
|
||||
|
|
@ -491,12 +488,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(Mutability::Mut, ref place) => {
|
||||
Rvalue::AddressOf(Mutability::Mut, place) => {
|
||||
self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place)
|
||||
| Rvalue::AddressOf(Mutability::Not, ref place) => {
|
||||
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, place)
|
||||
| Rvalue::AddressOf(Mutability::Not, place) => {
|
||||
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
||||
&self.ccx,
|
||||
&mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
|
||||
|
|
@ -564,7 +561,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
|
||||
Rvalue::ShallowInitBox(_, _) => {}
|
||||
|
||||
Rvalue::UnaryOp(_, ref operand) => {
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
let ty = operand.ty(self.body, self.tcx);
|
||||
if is_int_bool_or_char(ty) {
|
||||
// Int, bool, and char operations are fine.
|
||||
|
|
@ -575,8 +572,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(op, box (ref lhs, ref rhs))
|
||||
| Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
|
||||
Rvalue::BinaryOp(op, box (lhs, rhs))
|
||||
| Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
|
||||
let lhs_ty = lhs.ty(self.body, self.tcx);
|
||||
let rhs_ty = rhs.ty(self.body, self.tcx);
|
||||
|
||||
|
|
@ -585,13 +582,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
} else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
|
||||
assert_eq!(lhs_ty, rhs_ty);
|
||||
assert!(
|
||||
op == BinOp::Eq
|
||||
|| op == BinOp::Ne
|
||||
|| op == BinOp::Le
|
||||
|| op == BinOp::Lt
|
||||
|| op == BinOp::Ge
|
||||
|| op == BinOp::Gt
|
||||
|| op == BinOp::Offset
|
||||
matches!(
|
||||
op,
|
||||
BinOp::Eq
|
||||
| BinOp::Ne
|
||||
| BinOp::Le
|
||||
| BinOp::Lt
|
||||
| BinOp::Ge
|
||||
| BinOp::Gt
|
||||
| BinOp::Offset
|
||||
)
|
||||
);
|
||||
|
||||
self.check_op(ops::RawPtrComparison);
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
|
|||
}
|
||||
_ => { /* mark as unpromotable below */ }
|
||||
}
|
||||
} else if let TempState::Defined { ref mut uses, .. } = *temp {
|
||||
} else if let TempState::Defined { uses, .. } = temp {
|
||||
// We always allow borrows, even mutable ones, as we need
|
||||
// to promote mutable borrows of some ZSTs e.g., `&mut []`.
|
||||
let allowed_use = match context {
|
||||
|
|
@ -748,7 +748,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
if loc.statement_index < num_stmts {
|
||||
let (mut rvalue, source_info) = {
|
||||
let statement = &mut self.source[loc.block].statements[loc.statement_index];
|
||||
let StatementKind::Assign(box (_, ref mut rhs)) = statement.kind else {
|
||||
let StatementKind::Assign(box (_, rhs)) = &mut statement.kind else {
|
||||
span_bug!(
|
||||
statement.source_info.span,
|
||||
"{:?} is not an assignment",
|
||||
|
|
@ -778,9 +778,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
self.source[loc.block].terminator().clone()
|
||||
} else {
|
||||
let terminator = self.source[loc.block].terminator_mut();
|
||||
let target = match terminator.kind {
|
||||
TerminatorKind::Call { target: Some(target), .. } => target,
|
||||
ref kind => {
|
||||
let target = match &terminator.kind {
|
||||
TerminatorKind::Call { target: Some(target), .. } => *target,
|
||||
kind => {
|
||||
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
|
||||
}
|
||||
};
|
||||
|
|
@ -814,7 +814,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
..terminator
|
||||
};
|
||||
}
|
||||
ref kind => {
|
||||
kind => {
|
||||
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
|
||||
}
|
||||
};
|
||||
|
|
@ -847,54 +847,50 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
let local_decls = &mut self.source.local_decls;
|
||||
let loc = candidate.location;
|
||||
let statement = &mut blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box (
|
||||
_,
|
||||
Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
|
||||
)) => {
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
let ty = local_decls[place.local].ty;
|
||||
let span = statement.source_info.span;
|
||||
let StatementKind::Assign(box (_, Rvalue::Ref(region, borrow_kind, place))) = &mut statement.kind else {
|
||||
bug!()
|
||||
};
|
||||
|
||||
let ref_ty = tcx.mk_ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
|
||||
);
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
let ty = local_decls[place.local].ty;
|
||||
let span = statement.source_info.span;
|
||||
|
||||
*region = tcx.lifetimes.re_erased;
|
||||
let ref_ty = tcx.mk_ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
|
||||
);
|
||||
|
||||
let mut projection = vec![PlaceElem::Deref];
|
||||
projection.extend(place.projection);
|
||||
place.projection = tcx.intern_place_elems(&projection);
|
||||
*region = tcx.lifetimes.re_erased;
|
||||
|
||||
// Create a temp to hold the promoted reference.
|
||||
// This is because `*r` requires `r` to be a local,
|
||||
// otherwise we would use the `promoted` directly.
|
||||
let mut promoted_ref = LocalDecl::new(ref_ty, span);
|
||||
promoted_ref.source_info = statement.source_info;
|
||||
let promoted_ref = local_decls.push(promoted_ref);
|
||||
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
|
||||
let mut projection = vec![PlaceElem::Deref];
|
||||
projection.extend(place.projection);
|
||||
place.projection = tcx.intern_place_elems(&projection);
|
||||
|
||||
let promoted_ref_statement = Statement {
|
||||
source_info: statement.source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
Place::from(promoted_ref),
|
||||
Rvalue::Use(promoted_operand(ref_ty, span)),
|
||||
))),
|
||||
};
|
||||
self.extra_statements.push((loc, promoted_ref_statement));
|
||||
// Create a temp to hold the promoted reference.
|
||||
// This is because `*r` requires `r` to be a local,
|
||||
// otherwise we would use the `promoted` directly.
|
||||
let mut promoted_ref = LocalDecl::new(ref_ty, span);
|
||||
promoted_ref.source_info = statement.source_info;
|
||||
let promoted_ref = local_decls.push(promoted_ref);
|
||||
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
|
||||
|
||||
Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
borrow_kind,
|
||||
Place {
|
||||
local: mem::replace(&mut place.local, promoted_ref),
|
||||
projection: List::empty(),
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
let promoted_ref_statement = Statement {
|
||||
source_info: statement.source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
Place::from(promoted_ref),
|
||||
Rvalue::Use(promoted_operand(ref_ty, span)),
|
||||
))),
|
||||
};
|
||||
self.extra_statements.push((loc, promoted_ref_statement));
|
||||
|
||||
Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
*borrow_kind,
|
||||
Place {
|
||||
local: mem::replace(&mut place.local, promoted_ref),
|
||||
projection: List::empty(),
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(self.new_block(), START_BLOCK);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
//! Validates the MIR to ensure that invariants are upheld.
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::mir::interpret::Scalar;
|
||||
use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
|
||||
|
|
@ -18,7 +19,7 @@ use rustc_mir_dataflow::storage::always_storage_live_locals;
|
|||
use rustc_mir_dataflow::{Analysis, ResultsCursor};
|
||||
use rustc_target::abi::{Size, VariantIdx};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum EdgeKind {
|
||||
Unwind,
|
||||
Normal,
|
||||
|
|
@ -57,18 +58,20 @@ impl<'tcx> MirPass<'tcx> for Validator {
|
|||
.iterate_to_fixpoint()
|
||||
.into_results_cursor(body);
|
||||
|
||||
TypeChecker {
|
||||
let mut checker = TypeChecker {
|
||||
when: &self.when,
|
||||
body,
|
||||
tcx,
|
||||
param_env,
|
||||
mir_phase,
|
||||
unwind_edge_count: 0,
|
||||
reachable_blocks: traversal::reachable_as_bitset(body),
|
||||
storage_liveness,
|
||||
place_cache: Vec::new(),
|
||||
value_cache: Vec::new(),
|
||||
}
|
||||
.visit_body(body);
|
||||
};
|
||||
checker.visit_body(body);
|
||||
checker.check_cleanup_control_flow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +81,7 @@ struct TypeChecker<'a, 'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
mir_phase: MirPhase,
|
||||
unwind_edge_count: usize,
|
||||
reachable_blocks: BitSet<BasicBlock>,
|
||||
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
|
||||
place_cache: Vec<PlaceRef<'tcx>>,
|
||||
|
|
@ -102,7 +106,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
|
||||
fn check_edge(&mut self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
|
||||
if bb == START_BLOCK {
|
||||
self.fail(location, "start block must not have predecessors")
|
||||
}
|
||||
|
|
@ -111,10 +115,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
match (src.is_cleanup, bb.is_cleanup, edge_kind) {
|
||||
// Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
|
||||
(false, false, EdgeKind::Normal)
|
||||
// Non-cleanup blocks can jump to cleanup blocks along unwind edges
|
||||
| (false, true, EdgeKind::Unwind)
|
||||
// Cleanup blocks can jump to cleanup blocks along non-unwind edges
|
||||
| (true, true, EdgeKind::Normal) => {}
|
||||
// Non-cleanup blocks can jump to cleanup blocks along unwind edges
|
||||
(false, true, EdgeKind::Unwind) => {
|
||||
self.unwind_edge_count += 1;
|
||||
}
|
||||
// All other jumps are invalid
|
||||
_ => {
|
||||
self.fail(
|
||||
|
|
@ -134,6 +140,88 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_cleanup_control_flow(&self) {
|
||||
if self.unwind_edge_count <= 1 {
|
||||
return;
|
||||
}
|
||||
let doms = self.body.basic_blocks.dominators();
|
||||
let mut post_contract_node = FxHashMap::default();
|
||||
// Reusing the allocation across invocations of the closure
|
||||
let mut dom_path = vec![];
|
||||
let mut get_post_contract_node = |mut bb| {
|
||||
let root = loop {
|
||||
if let Some(root) = post_contract_node.get(&bb) {
|
||||
break *root;
|
||||
}
|
||||
let parent = doms.immediate_dominator(bb);
|
||||
dom_path.push(bb);
|
||||
if !self.body.basic_blocks[parent].is_cleanup {
|
||||
break bb;
|
||||
}
|
||||
bb = parent;
|
||||
};
|
||||
for bb in dom_path.drain(..) {
|
||||
post_contract_node.insert(bb, root);
|
||||
}
|
||||
root
|
||||
};
|
||||
|
||||
let mut parent = IndexVec::from_elem(None, &self.body.basic_blocks);
|
||||
for (bb, bb_data) in self.body.basic_blocks.iter_enumerated() {
|
||||
if !bb_data.is_cleanup || !self.reachable_blocks.contains(bb) {
|
||||
continue;
|
||||
}
|
||||
let bb = get_post_contract_node(bb);
|
||||
for s in bb_data.terminator().successors() {
|
||||
let s = get_post_contract_node(s);
|
||||
if s == bb {
|
||||
continue;
|
||||
}
|
||||
let parent = &mut parent[bb];
|
||||
match parent {
|
||||
None => {
|
||||
*parent = Some(s);
|
||||
}
|
||||
Some(e) if *e == s => (),
|
||||
Some(e) => self.fail(
|
||||
Location { block: bb, statement_index: 0 },
|
||||
format!(
|
||||
"Cleanup control flow violation: The blocks dominated by {:?} have edges to both {:?} and {:?}",
|
||||
bb,
|
||||
s,
|
||||
*e
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for cycles
|
||||
let mut stack = FxHashSet::default();
|
||||
for i in 0..parent.len() {
|
||||
let mut bb = BasicBlock::from_usize(i);
|
||||
stack.clear();
|
||||
stack.insert(bb);
|
||||
loop {
|
||||
let Some(parent)= parent[bb].take() else {
|
||||
break
|
||||
};
|
||||
let no_cycle = stack.insert(parent);
|
||||
if !no_cycle {
|
||||
self.fail(
|
||||
Location { block: bb, statement_index: 0 },
|
||||
format!(
|
||||
"Cleanup control flow violation: Cycle involving edge {:?} -> {:?}",
|
||||
bb, parent,
|
||||
),
|
||||
);
|
||||
break;
|
||||
}
|
||||
bb = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if src can be assigned into dest.
|
||||
/// This is not precise, it will accept some incorrect assignments.
|
||||
fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>;
|
|||
#[macro_export]
|
||||
macro_rules! define_id_collections {
|
||||
($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => {
|
||||
pub type $map_name<T> = $crate::fx::FxHashMap<$key, T>;
|
||||
pub type $set_name = $crate::fx::FxHashSet<$key>;
|
||||
pub type $map_name<T> = $crate::unord::UnordMap<$key, T>;
|
||||
pub type $set_name = $crate::unord::UnordSet<$key>;
|
||||
pub type $entry_name<'a, T> = $crate::fx::StdEntry<'a, $key, T>;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,10 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
|
|||
// This loop computes the semi[w] for w.
|
||||
semi[w] = w;
|
||||
for v in graph.predecessors(pre_order_to_real[w]) {
|
||||
let v = real_to_pre_order[v].unwrap();
|
||||
// Reachable vertices may have unreachable predecessors, so ignore any of them
|
||||
let Some(v) = real_to_pre_order[v] else {
|
||||
continue
|
||||
};
|
||||
|
||||
// eval returns a vertex x from which semi[x] is minimum among
|
||||
// vertices semi[v] +> x *> v.
|
||||
|
|
@ -268,10 +271,6 @@ pub struct Dominators<N: Idx> {
|
|||
}
|
||||
|
||||
impl<Node: Idx> Dominators<Node> {
|
||||
pub fn dummy() -> Self {
|
||||
Self { post_order_rank: IndexVec::new(), immediate_dominators: IndexVec::new() }
|
||||
}
|
||||
|
||||
pub fn is_reachable(&self, node: Node) -> bool {
|
||||
self.immediate_dominators[node].is_some()
|
||||
}
|
||||
|
|
@ -296,7 +295,7 @@ impl<Node: Idx> Dominators<Node> {
|
|||
/// of two unrelated nodes will also be consistent, but otherwise the order has no
|
||||
/// meaning.) This method cannot be used to determine if either Node dominates the other.
|
||||
pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
|
||||
self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
|
||||
self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(
|
|||
"counter={:?} expected={:?} edge_index={:?} edge={:?}",
|
||||
counter, expected_incoming[counter], edge_index, edge
|
||||
);
|
||||
match expected_incoming[counter] {
|
||||
(ref e, ref n) => {
|
||||
match &expected_incoming[counter] {
|
||||
(e, n) => {
|
||||
assert!(e == &edge.data);
|
||||
assert!(n == graph.node_data(edge.source()));
|
||||
assert!(start_index == edge.target);
|
||||
|
|
@ -88,8 +88,8 @@ fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(
|
|||
"counter={:?} expected={:?} edge_index={:?} edge={:?}",
|
||||
counter, expected_outgoing[counter], edge_index, edge
|
||||
);
|
||||
match expected_outgoing[counter] {
|
||||
(ref e, ref n) => {
|
||||
match &expected_outgoing[counter] {
|
||||
(e, n) => {
|
||||
assert!(e == &edge.data);
|
||||
assert!(start_index == edge.source);
|
||||
assert!(n == graph.node_data(edge.target));
|
||||
|
|
|
|||
|
|
@ -317,12 +317,12 @@ where
|
|||
_node: G::Node,
|
||||
_prior_status: Option<NodeStatus>,
|
||||
) -> ControlFlow<Self::BreakVal> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Called after all nodes reachable from this one have been examined.
|
||||
fn node_settled(&mut self, _node: G::Node) -> ControlFlow<Self::BreakVal> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Behave as if no edges exist from `source` to `target`.
|
||||
|
|
@ -346,8 +346,8 @@ where
|
|||
prior_status: Option<NodeStatus>,
|
||||
) -> ControlFlow<Self::BreakVal> {
|
||||
match prior_status {
|
||||
Some(NodeStatus::Visited) => ControlFlow::BREAK,
|
||||
_ => ControlFlow::CONTINUE,
|
||||
Some(NodeStatus::Visited) => ControlFlow::Break(()),
|
||||
_ => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#![feature(associated_type_bounds)]
|
||||
#![feature(auto_traits)]
|
||||
#![feature(cell_leak)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
|
||||
use std::borrow::Borrow;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::Debug;
|
||||
use std::mem;
|
||||
use std::ops::{Bound, Index, IndexMut, RangeBounds};
|
||||
|
|
@ -171,7 +170,7 @@ impl<K: Ord, V> SortedMap<K, V> {
|
|||
where
|
||||
F: Fn(&mut K),
|
||||
{
|
||||
self.data.iter_mut().map(|&mut (ref mut k, _)| k).for_each(f);
|
||||
self.data.iter_mut().map(|(k, _)| k).for_each(f);
|
||||
}
|
||||
|
||||
/// Inserts a presorted range of elements into the map. If the range can be
|
||||
|
|
@ -232,10 +231,10 @@ impl<K: Ord, V> SortedMap<K, V> {
|
|||
R: RangeBounds<K>,
|
||||
{
|
||||
let start = match range.start_bound() {
|
||||
Bound::Included(ref k) => match self.lookup_index_for(k) {
|
||||
Bound::Included(k) => match self.lookup_index_for(k) {
|
||||
Ok(index) | Err(index) => index,
|
||||
},
|
||||
Bound::Excluded(ref k) => match self.lookup_index_for(k) {
|
||||
Bound::Excluded(k) => match self.lookup_index_for(k) {
|
||||
Ok(index) => index + 1,
|
||||
Err(index) => index,
|
||||
},
|
||||
|
|
@ -243,11 +242,11 @@ impl<K: Ord, V> SortedMap<K, V> {
|
|||
};
|
||||
|
||||
let end = match range.end_bound() {
|
||||
Bound::Included(ref k) => match self.lookup_index_for(k) {
|
||||
Bound::Included(k) => match self.lookup_index_for(k) {
|
||||
Ok(index) => index + 1,
|
||||
Err(index) => index,
|
||||
},
|
||||
Bound::Excluded(ref k) => match self.lookup_index_for(k) {
|
||||
Bound::Excluded(k) => match self.lookup_index_for(k) {
|
||||
Ok(index) | Err(index) => index,
|
||||
},
|
||||
Bound::Unbounded => self.data.len(),
|
||||
|
|
@ -302,7 +301,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for SortedMap<K, V> {
|
|||
let mut data: Vec<(K, V)> = iter.into_iter().collect();
|
||||
|
||||
data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
|
||||
data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| k1.cmp(k2) == Ordering::Equal);
|
||||
data.dedup_by(|(k1, _), (k2, _)| k1 == k2);
|
||||
|
||||
SortedMap { data }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,13 +63,13 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
|
|||
/// Returns an iterator over the items in the map in insertion order.
|
||||
#[inline]
|
||||
pub fn iter(&self) -> impl '_ + DoubleEndedIterator<Item = (&K, &V)> {
|
||||
self.items.iter().map(|(ref k, ref v)| (k, v))
|
||||
self.items.iter().map(|(k, v)| (k, v))
|
||||
}
|
||||
|
||||
/// Returns an iterator over the items in the map in insertion order along with their indices.
|
||||
#[inline]
|
||||
pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator<Item = (I, (&K, &V))> {
|
||||
self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v)))
|
||||
self.items.iter_enumerated().map(|(i, (k, v))| (i, (k, v)))
|
||||
}
|
||||
|
||||
/// Returns the item in the map with the given index.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ fn test_sorted_index_multi_map() {
|
|||
let set: SortedIndexMultiMap<usize, _, _> = entries.iter().copied().collect();
|
||||
|
||||
// Insertion order is preserved.
|
||||
assert!(entries.iter().map(|(ref k, ref v)| (k, v)).eq(set.iter()));
|
||||
assert!(entries.iter().map(|(k, v)| (k, v)).eq(set.iter()));
|
||||
|
||||
// Indexing
|
||||
for (i, expect) in entries.iter().enumerate() {
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ impl<T: PartialEq> TinyList<T> {
|
|||
|
||||
#[inline]
|
||||
pub fn remove(&mut self, data: &T) -> bool {
|
||||
self.head = match self.head {
|
||||
Some(ref mut head) if head.data == *data => head.next.take().map(|x| *x),
|
||||
Some(ref mut head) => return head.remove_next(data),
|
||||
self.head = match &mut self.head {
|
||||
Some(head) if head.data == *data => head.next.take().map(|x| *x),
|
||||
Some(head) => return head.remove_next(data),
|
||||
None => return false,
|
||||
};
|
||||
true
|
||||
|
|
@ -48,7 +48,7 @@ impl<T: PartialEq> TinyList<T> {
|
|||
#[inline]
|
||||
pub fn contains(&self, data: &T) -> bool {
|
||||
let mut elem = self.head.as_ref();
|
||||
while let Some(ref e) = elem {
|
||||
while let Some(e) = elem {
|
||||
if &e.data == data {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -65,15 +65,14 @@ struct Element<T> {
|
|||
}
|
||||
|
||||
impl<T: PartialEq> Element<T> {
|
||||
fn remove_next(&mut self, data: &T) -> bool {
|
||||
let mut n = self;
|
||||
fn remove_next(mut self: &mut Self, data: &T) -> bool {
|
||||
loop {
|
||||
match n.next {
|
||||
match self.next {
|
||||
Some(ref mut next) if next.data == *data => {
|
||||
n.next = next.next.take();
|
||||
self.next = next.next.take();
|
||||
return true;
|
||||
}
|
||||
Some(ref mut next) => n = next,
|
||||
Some(ref mut next) => self = next,
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use test::{black_box, Bencher};
|
|||
impl<T> TinyList<T> {
|
||||
fn len(&self) -> usize {
|
||||
let (mut elem, mut count) = (self.head.as_ref(), 0);
|
||||
while let Some(ref e) = elem {
|
||||
while let Some(e) = elem {
|
||||
count += 1;
|
||||
elem = e.next.as_deref();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,15 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
|||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
collections::hash_map::Entry,
|
||||
hash::Hash,
|
||||
iter::{Product, Sum},
|
||||
ops::Index,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
fingerprint::Fingerprint,
|
||||
stable_hasher::{HashStable, StableHasher, ToStableHashKey},
|
||||
stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey},
|
||||
};
|
||||
|
||||
/// `UnordItems` is the order-less version of `Iterator`. It only contains methods
|
||||
|
|
@ -38,17 +40,17 @@ impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn all<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
|
||||
pub fn all<F: Fn(T) -> bool>(mut self, f: F) -> bool {
|
||||
self.0.all(f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn any<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
|
||||
pub fn any<F: Fn(T) -> bool>(mut self, f: F) -> bool {
|
||||
self.0.any(f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn filter<U, F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
|
||||
pub fn filter<F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
|
||||
UnordItems(self.0.filter(f))
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +98,15 @@ impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
|
|||
pub fn count(self) -> usize {
|
||||
self.0.count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn flat_map<U, F, O>(self, f: F) -> UnordItems<O, impl Iterator<Item = O>>
|
||||
where
|
||||
U: IntoIterator<Item = O>,
|
||||
F: Fn(T) -> U,
|
||||
{
|
||||
UnordItems(self.0.flat_map(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
|
||||
|
|
@ -147,6 +158,7 @@ pub struct UnordSet<V: Eq + Hash> {
|
|||
}
|
||||
|
||||
impl<V: Eq + Hash> Default for UnordSet<V> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self { inner: FxHashSet::default() }
|
||||
}
|
||||
|
|
@ -178,7 +190,16 @@ impl<V: Eq + Hash> UnordSet<V> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn items(&self) -> UnordItems<&V, impl Iterator<Item = &V>> {
|
||||
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> bool
|
||||
where
|
||||
V: Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.inner.remove(k)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
|
||||
UnordItems(self.inner.iter())
|
||||
}
|
||||
|
||||
|
|
@ -187,20 +208,75 @@ impl<V: Eq + Hash> UnordSet<V> {
|
|||
UnordItems(self.inner.into_iter())
|
||||
}
|
||||
|
||||
/// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`).
|
||||
///
|
||||
/// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
|
||||
/// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
|
||||
/// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
|
||||
/// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup).
|
||||
#[inline]
|
||||
pub fn to_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V>
|
||||
where
|
||||
V: ToStableHashKey<HCX>,
|
||||
{
|
||||
to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&x| x)
|
||||
}
|
||||
|
||||
/// Returns the items of this set in stable sort order (as defined by
|
||||
/// `StableOrd`). This method is much more efficient than
|
||||
/// `into_sorted` because it does not need to transform keys to their
|
||||
/// `ToStableHashKey` equivalent.
|
||||
#[inline]
|
||||
pub fn to_sorted_stable_ord(&self) -> Vec<V>
|
||||
where
|
||||
V: Ord + StableOrd + Copy,
|
||||
{
|
||||
let mut items: Vec<V> = self.inner.iter().copied().collect();
|
||||
items.sort_unstable();
|
||||
items
|
||||
}
|
||||
|
||||
/// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`).
|
||||
///
|
||||
/// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
|
||||
/// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
|
||||
/// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
|
||||
/// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup).
|
||||
#[inline]
|
||||
pub fn into_sorted<HCX>(self, hcx: &HCX, cache_sort_key: bool) -> Vec<V>
|
||||
where
|
||||
V: ToStableHashKey<HCX>,
|
||||
{
|
||||
to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |x| x)
|
||||
}
|
||||
|
||||
// We can safely extend this UnordSet from a set of unordered values because that
|
||||
// won't expose the internal ordering anywhere.
|
||||
#[inline]
|
||||
pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
|
||||
self.inner.extend(items.0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
self.inner.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Hash + Eq> Extend<V> for UnordSet<V> {
|
||||
#[inline]
|
||||
fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
|
||||
self.inner.extend(iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Hash + Eq> FromIterator<V> for UnordSet<V> {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
|
||||
UnordSet { inner: FxHashSet::from_iter(iter) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
|
|
@ -223,17 +299,33 @@ pub struct UnordMap<K: Eq + Hash, V> {
|
|||
}
|
||||
|
||||
impl<K: Eq + Hash, V> Default for UnordMap<K, V> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self { inner: FxHashMap::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq, V> Extend<(K, V)> for UnordMap<K, V> {
|
||||
#[inline]
|
||||
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
|
||||
self.inner.extend(iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq, V> FromIterator<(K, V)> for UnordMap<K, V> {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
|
||||
UnordMap { inner: FxHashMap::from_iter(iter) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq, V, I: Iterator<Item = (K, V)>> From<UnordItems<(K, V), I>> for UnordMap<K, V> {
|
||||
#[inline]
|
||||
fn from(items: UnordItems<(K, V), I>) -> Self {
|
||||
UnordMap { inner: FxHashMap::from_iter(items.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V> UnordMap<K, V> {
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
|
|
@ -255,7 +347,44 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator<Item = (&K, &V)>> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
|
||||
self.inner.entry(key)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.inner.get(k)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.inner.get_mut(k)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.inner.remove(k)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
|
||||
UnordItems(self.inner.iter())
|
||||
}
|
||||
|
||||
|
|
@ -270,6 +399,77 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
|
|||
pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) {
|
||||
self.inner.extend(items.0)
|
||||
}
|
||||
|
||||
/// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`).
|
||||
///
|
||||
/// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
|
||||
/// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
|
||||
/// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
|
||||
/// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup).
|
||||
#[inline]
|
||||
pub fn to_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)>
|
||||
where
|
||||
K: ToStableHashKey<HCX>,
|
||||
{
|
||||
to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k)
|
||||
}
|
||||
|
||||
/// Returns the entries of this map in stable sort order (as defined by `StableOrd`).
|
||||
/// This method can be much more efficient than `into_sorted` because it does not need
|
||||
/// to transform keys to their `ToStableHashKey` equivalent.
|
||||
#[inline]
|
||||
pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)>
|
||||
where
|
||||
K: Ord + StableOrd + Copy,
|
||||
{
|
||||
let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect();
|
||||
items.sort_unstable_by_key(|&(k, _)| k);
|
||||
items
|
||||
}
|
||||
|
||||
/// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`).
|
||||
///
|
||||
/// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
|
||||
/// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
|
||||
/// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
|
||||
/// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup).
|
||||
#[inline]
|
||||
pub fn into_sorted<HCX>(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)>
|
||||
where
|
||||
K: ToStableHashKey<HCX>,
|
||||
{
|
||||
to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k)
|
||||
}
|
||||
|
||||
/// Returns the values of this map in stable sort order (as defined by K's
|
||||
/// `ToStableHashKey` implementation).
|
||||
///
|
||||
/// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
|
||||
/// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
|
||||
/// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
|
||||
/// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup).
|
||||
#[inline]
|
||||
pub fn values_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator<Item = &V>
|
||||
where
|
||||
K: ToStableHashKey<HCX>,
|
||||
{
|
||||
to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k)
|
||||
.into_iter()
|
||||
.map(|(_, v)| v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V>
|
||||
where
|
||||
K: Eq + Hash + Borrow<Q>,
|
||||
Q: Eq + Hash,
|
||||
{
|
||||
type Output = V;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, key: &Q) -> &V {
|
||||
&self.inner[key]
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> {
|
||||
|
|
@ -334,6 +534,12 @@ impl<T> Extend<T> for UnordBag<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, I: Iterator<Item = T>> From<UnordItems<T, I>> for UnordBag<T> {
|
||||
fn from(value: UnordItems<T, I>) -> Self {
|
||||
UnordBag { inner: Vec::from_iter(value.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
|
|
@ -341,6 +547,27 @@ impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_sorted_vec<HCX, T, K, I>(
|
||||
hcx: &HCX,
|
||||
iter: I,
|
||||
cache_sort_key: bool,
|
||||
extract_key: fn(&T) -> &K,
|
||||
) -> Vec<T>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
K: ToStableHashKey<HCX>,
|
||||
{
|
||||
let mut items: Vec<T> = iter.collect();
|
||||
if cache_sort_key {
|
||||
items.sort_by_cached_key(|x| extract_key(x).to_stable_hash_key(hcx));
|
||||
} else {
|
||||
items.sort_unstable_by_key(|x| extract_key(x).to_stable_hash_key(hcx));
|
||||
}
|
||||
|
||||
items
|
||||
}
|
||||
|
||||
fn hash_iter_order_independent<
|
||||
HCX,
|
||||
T: HashStable<HCX>,
|
||||
|
|
|
|||
|
|
@ -219,7 +219,6 @@ fn run_compiler(
|
|||
crate_cfg: cfg,
|
||||
crate_check_cfg: check_cfg,
|
||||
input: Input::File(PathBuf::new()),
|
||||
input_path: None,
|
||||
output_file: ofile,
|
||||
output_dir: odir,
|
||||
file_loader,
|
||||
|
|
@ -237,9 +236,8 @@ fn run_compiler(
|
|||
|
||||
match make_input(config.opts.error_format, &matches.free) {
|
||||
Err(reported) => return Err(reported),
|
||||
Ok(Some((input, input_file_path))) => {
|
||||
Ok(Some(input)) => {
|
||||
config.input = input;
|
||||
config.input_path = input_file_path;
|
||||
|
||||
callbacks.config(&mut config);
|
||||
}
|
||||
|
|
@ -261,14 +259,8 @@ fn run_compiler(
|
|||
describe_lints(compiler.session(), &lint_store, registered_lints);
|
||||
return;
|
||||
}
|
||||
let should_stop = print_crate_info(
|
||||
&***compiler.codegen_backend(),
|
||||
compiler.session(),
|
||||
None,
|
||||
compiler.output_dir(),
|
||||
compiler.output_file(),
|
||||
compiler.temps_dir(),
|
||||
);
|
||||
let should_stop =
|
||||
print_crate_info(&***compiler.codegen_backend(), compiler.session(), false);
|
||||
|
||||
if should_stop == Compilation::Stop {
|
||||
return;
|
||||
|
|
@ -290,18 +282,9 @@ fn run_compiler(
|
|||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sess = compiler.session();
|
||||
let should_stop = print_crate_info(
|
||||
&***compiler.codegen_backend(),
|
||||
sess,
|
||||
Some(compiler.input()),
|
||||
compiler.output_dir(),
|
||||
compiler.output_file(),
|
||||
compiler.temps_dir(),
|
||||
)
|
||||
.and_then(|| {
|
||||
list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input())
|
||||
})
|
||||
.and_then(|| try_process_rlink(sess, compiler));
|
||||
let should_stop = print_crate_info(&***compiler.codegen_backend(), sess, true)
|
||||
.and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader()))
|
||||
.and_then(|| try_process_rlink(sess, compiler));
|
||||
|
||||
if should_stop == Compilation::Stop {
|
||||
return sess.compile_status();
|
||||
|
|
@ -315,24 +298,12 @@ fn run_compiler(
|
|||
if ppm.needs_ast_map() {
|
||||
let expanded_crate = queries.expansion()?.borrow().0.clone();
|
||||
queries.global_ctxt()?.enter(|tcx| {
|
||||
pretty::print_after_hir_lowering(
|
||||
tcx,
|
||||
compiler.input(),
|
||||
&*expanded_crate,
|
||||
*ppm,
|
||||
compiler.output_file().as_deref(),
|
||||
);
|
||||
pretty::print_after_hir_lowering(tcx, &*expanded_crate, *ppm);
|
||||
Ok(())
|
||||
})?;
|
||||
} else {
|
||||
let krate = queries.parse()?.steal();
|
||||
pretty::print_after_parsing(
|
||||
sess,
|
||||
compiler.input(),
|
||||
&krate,
|
||||
*ppm,
|
||||
compiler.output_file().as_deref(),
|
||||
);
|
||||
pretty::print_after_parsing(sess, &krate, *ppm);
|
||||
}
|
||||
trace!("finished pretty-printing");
|
||||
return early_exit();
|
||||
|
|
@ -357,21 +328,17 @@ fn run_compiler(
|
|||
}
|
||||
}
|
||||
|
||||
queries.expansion()?;
|
||||
queries.global_ctxt()?;
|
||||
if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.prepare_outputs()?;
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
{
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.global_ctxt()?;
|
||||
|
||||
if sess.opts.unstable_opts.no_analysis {
|
||||
return early_exit();
|
||||
}
|
||||
|
|
@ -384,9 +351,9 @@ fn run_compiler(
|
|||
save::process_crate(
|
||||
tcx,
|
||||
crate_name,
|
||||
compiler.input(),
|
||||
&sess.io.input,
|
||||
None,
|
||||
DumpHandler::new(compiler.output_dir().as_deref(), crate_name),
|
||||
DumpHandler::new(sess.io.output_dir.as_deref(), crate_name),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
|
@ -439,7 +406,7 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>)
|
|||
fn make_input(
|
||||
error_format: ErrorOutputType,
|
||||
free_matches: &[String],
|
||||
) -> Result<Option<(Input, Option<PathBuf>)>, ErrorGuaranteed> {
|
||||
) -> Result<Option<Input>, ErrorGuaranteed> {
|
||||
if free_matches.len() == 1 {
|
||||
let ifile = &free_matches[0];
|
||||
if ifile == "-" {
|
||||
|
|
@ -461,12 +428,12 @@ fn make_input(
|
|||
let line = isize::from_str_radix(&line, 10)
|
||||
.expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
|
||||
let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
|
||||
Ok(Some((Input::Str { name: file_name, input: src }, None)))
|
||||
Ok(Some(Input::Str { name: file_name, input: src }))
|
||||
} else {
|
||||
Ok(Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None)))
|
||||
Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
|
||||
}
|
||||
} else {
|
||||
Ok(Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)))))
|
||||
Ok(Some(Input::File(PathBuf::from(ifile))))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
|
|
@ -560,7 +527,7 @@ fn show_content_with_pager(content: &str) {
|
|||
|
||||
pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
|
||||
if sess.opts.unstable_opts.link_only {
|
||||
if let Input::File(file) = compiler.input() {
|
||||
if let Input::File(file) = &sess.io.input {
|
||||
// FIXME: #![crate_type] and #![crate_name] support not implemented yet
|
||||
sess.init_crate_types(collect_crate_types(sess, &[]));
|
||||
let outputs = compiler.build_output_filenames(sess, &[]);
|
||||
|
|
@ -601,13 +568,9 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
|
|||
}
|
||||
}
|
||||
|
||||
pub fn list_metadata(
|
||||
sess: &Session,
|
||||
metadata_loader: &dyn MetadataLoader,
|
||||
input: &Input,
|
||||
) -> Compilation {
|
||||
pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation {
|
||||
if sess.opts.unstable_opts.ls {
|
||||
match *input {
|
||||
match sess.io.input {
|
||||
Input::File(ref ifile) => {
|
||||
let path = &(*ifile);
|
||||
let mut v = Vec::new();
|
||||
|
|
@ -627,10 +590,7 @@ pub fn list_metadata(
|
|||
fn print_crate_info(
|
||||
codegen_backend: &dyn CodegenBackend,
|
||||
sess: &Session,
|
||||
input: Option<&Input>,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
temps_dir: &Option<PathBuf>,
|
||||
parse_attrs: bool,
|
||||
) -> Compilation {
|
||||
use rustc_session::config::PrintRequest::*;
|
||||
// NativeStaticLibs and LinkArgs are special - printed during linking
|
||||
|
|
@ -639,18 +599,17 @@ fn print_crate_info(
|
|||
return Compilation::Continue;
|
||||
}
|
||||
|
||||
let attrs = match input {
|
||||
None => None,
|
||||
Some(input) => {
|
||||
let result = parse_crate_attrs(sess, input);
|
||||
match result {
|
||||
Ok(attrs) => Some(attrs),
|
||||
Err(mut parse_error) => {
|
||||
parse_error.emit();
|
||||
return Compilation::Stop;
|
||||
}
|
||||
let attrs = if parse_attrs {
|
||||
let result = parse_crate_attrs(sess);
|
||||
match result {
|
||||
Ok(attrs) => Some(attrs),
|
||||
Err(mut parse_error) => {
|
||||
parse_error.emit();
|
||||
return Compilation::Stop;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
for req in &sess.opts.prints {
|
||||
match *req {
|
||||
|
|
@ -665,14 +624,9 @@ fn print_crate_info(
|
|||
println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
|
||||
}
|
||||
FileNames | CrateName => {
|
||||
let input = input.unwrap_or_else(|| {
|
||||
early_error(ErrorOutputType::default(), "no input file provided")
|
||||
});
|
||||
let attrs = attrs.as_ref().unwrap();
|
||||
let t_outputs = rustc_interface::util::build_output_filenames(
|
||||
input, odir, ofile, temps_dir, attrs, sess,
|
||||
);
|
||||
let id = rustc_session::output::find_crate_name(sess, attrs, input);
|
||||
let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess);
|
||||
let id = rustc_session::output::find_crate_name(sess, attrs);
|
||||
if *req == PrintRequest::CrateName {
|
||||
println!("{id}");
|
||||
continue;
|
||||
|
|
@ -1108,8 +1062,8 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
|||
Some(matches)
|
||||
}
|
||||
|
||||
fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::AttrVec> {
|
||||
match input {
|
||||
fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
|
||||
match &sess.io.input {
|
||||
Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess),
|
||||
Input::Str { name, input } => rustc_parse::parse_crate_attrs_from_source_str(
|
||||
name.clone(),
|
||||
|
|
|
|||
|
|
@ -9,14 +9,13 @@ use rustc_hir_pretty as pprust_hir;
|
|||
use rustc_middle::hir::map as hir_map;
|
||||
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
|
||||
use rustc_session::config::{PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::FileName;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
|
||||
pub use self::PpMode::*;
|
||||
pub use self::PpSourceMode::*;
|
||||
|
|
@ -345,8 +344,8 @@ impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
|
||||
let src_name = input.source_name();
|
||||
fn get_source(sess: &Session) -> (String, FileName) {
|
||||
let src_name = sess.io.input.source_name();
|
||||
let src = String::clone(
|
||||
sess.source_map()
|
||||
.get_source_file(&src_name)
|
||||
|
|
@ -358,8 +357,8 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
|
|||
(src, src_name)
|
||||
}
|
||||
|
||||
fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) {
|
||||
match ofile {
|
||||
fn write_or_print(out: &str, sess: &Session) {
|
||||
match &sess.io.output_file {
|
||||
None => print!("{out}"),
|
||||
Some(p) => {
|
||||
if let Err(e) = std::fs::write(p, out) {
|
||||
|
|
@ -372,14 +371,8 @@ fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_after_parsing(
|
||||
sess: &Session,
|
||||
input: &Input,
|
||||
krate: &ast::Crate,
|
||||
ppm: PpMode,
|
||||
ofile: Option<&Path>,
|
||||
) {
|
||||
let (src, src_name) = get_source(input, sess);
|
||||
pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) {
|
||||
let (src, src_name) = get_source(sess);
|
||||
|
||||
let out = match ppm {
|
||||
Source(s) => {
|
||||
|
|
@ -407,22 +400,16 @@ pub fn print_after_parsing(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
write_or_print(&out, ofile, sess);
|
||||
write_or_print(&out, sess);
|
||||
}
|
||||
|
||||
pub fn print_after_hir_lowering<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
input: &Input,
|
||||
krate: &ast::Crate,
|
||||
ppm: PpMode,
|
||||
ofile: Option<&Path>,
|
||||
) {
|
||||
pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm: PpMode) {
|
||||
if ppm.needs_analysis() {
|
||||
abort_on_err(print_with_analysis(tcx, ppm, ofile), tcx.sess);
|
||||
abort_on_err(print_with_analysis(tcx, ppm), tcx.sess);
|
||||
return;
|
||||
}
|
||||
|
||||
let (src, src_name) = get_source(input, tcx.sess);
|
||||
let (src, src_name) = get_source(tcx.sess);
|
||||
|
||||
let out = match ppm {
|
||||
Source(s) => {
|
||||
|
|
@ -474,18 +461,14 @@ pub fn print_after_hir_lowering<'tcx>(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
write_or_print(&out, ofile, tcx.sess);
|
||||
write_or_print(&out, tcx.sess);
|
||||
}
|
||||
|
||||
// In an ideal world, this would be a public function called by the driver after
|
||||
// analysis is performed. However, we want to call `phase_3_run_analysis_passes`
|
||||
// with a different callback than the standard driver, so that isn't easy.
|
||||
// Instead, we call that function ourselves.
|
||||
fn print_with_analysis(
|
||||
tcx: TyCtxt<'_>,
|
||||
ppm: PpMode,
|
||||
ofile: Option<&Path>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuaranteed> {
|
||||
tcx.analysis(())?;
|
||||
let out = match ppm {
|
||||
Mir => {
|
||||
|
|
@ -518,7 +501,7 @@ fn print_with_analysis(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
write_or_print(&out, ofile, tcx.sess);
|
||||
write_or_print(&out, tcx.sess);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -508,6 +508,7 @@ E0787: include_str!("./error_codes/E0787.md"),
|
|||
E0788: include_str!("./error_codes/E0788.md"),
|
||||
E0790: include_str!("./error_codes/E0790.md"),
|
||||
E0791: include_str!("./error_codes/E0791.md"),
|
||||
E0792: include_str!("./error_codes/E0792.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
|
|
|
|||
|
|
@ -1 +1,46 @@
|
|||
#### This error code is internal to the compiler and will not be emitted with normal Rust code.
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
This error code shows the variance of a type's generic parameters.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
// NOTE: this feature is perma-unstable and should *only* be used for
|
||||
// testing purposes.
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_variance]
|
||||
struct Foo<'a, T> { // error: deliberate error to display type's variance
|
||||
t: &'a mut T,
|
||||
}
|
||||
```
|
||||
|
||||
which produces the following error:
|
||||
|
||||
```text
|
||||
error: [-, o]
|
||||
--> <anon>:4:1
|
||||
|
|
||||
4 | struct Foo<'a, T> {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
*Note that while `#[rustc_variance]` still exists and is used within the*
|
||||
*compiler, it no longer is marked as `E0208` and instead has no error code.*
|
||||
|
||||
This error is deliberately triggered with the `#[rustc_variance]` attribute
|
||||
(`#![feature(rustc_attrs)]` must be enabled) and helps to show you the variance
|
||||
of the type's generic parameters. You can read more about variance and
|
||||
subtyping in [this section of the Rustnomicon]. For a more in depth look at
|
||||
variance (including a more complete list of common variances) see
|
||||
[this section of the Reference]. For information on how variance is implemented
|
||||
in the compiler, see [this section of `rustc-dev-guide`].
|
||||
|
||||
This error can be easily fixed by removing the `#[rustc_variance]` attribute,
|
||||
the compiler's suggestion to comment it out can be applied automatically with
|
||||
`rustfix`.
|
||||
|
||||
[this section of the Rustnomicon]: https://doc.rust-lang.org/nomicon/subtyping.html
|
||||
[this section of the Reference]: https://doc.rust-lang.org/reference/subtyping.html#variance
|
||||
[this section of `rustc-dev-guide`]: https://rustc-dev-guide.rust-lang.org/variance.html
|
||||
|
|
|
|||
60
compiler/rustc_error_codes/src/error_codes/E0792.md
Normal file
60
compiler/rustc_error_codes/src/error_codes/E0792.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
A type alias impl trait can only have its hidden type assigned
|
||||
when used fully generically (and within their defining scope).
|
||||
This means
|
||||
|
||||
```compile_fail,E0792
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Foo<T> = impl std::fmt::Debug;
|
||||
|
||||
fn foo() -> Foo<u32> {
|
||||
5u32
|
||||
}
|
||||
```
|
||||
|
||||
is not accepted. If it were accepted, one could create unsound situations like
|
||||
|
||||
```compile_fail,E0792
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Foo<T> = impl Default;
|
||||
|
||||
fn foo() -> Foo<u32> {
|
||||
5u32
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Foo::<&'static mut String>::default();
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Instead you need to make the function generic:
|
||||
|
||||
```
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Foo<T> = impl std::fmt::Debug;
|
||||
|
||||
fn foo<U>() -> Foo<U> {
|
||||
5u32
|
||||
}
|
||||
```
|
||||
|
||||
This means that no matter the generic parameter to `foo`,
|
||||
the hidden type will always be `u32`.
|
||||
If you want to link the generic parameter to the hidden type,
|
||||
you can do that, too:
|
||||
|
||||
|
||||
```
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
type Foo<T: Debug> = impl Debug;
|
||||
|
||||
fn foo<U: Debug>() -> Foo<U> {
|
||||
Vec::<U>::new()
|
||||
}
|
||||
```
|
||||
|
|
@ -88,4 +88,5 @@ ast_passes_ty_alias_without_body =
|
|||
ast_passes_fn_without_body =
|
||||
free function without a body
|
||||
.suggestion = provide a definition for the function
|
||||
.extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
|
||||
|
||||
ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
|
||||
|
|
|
|||
|
|
@ -120,3 +120,7 @@ borrowck_cannot_move_when_borrowed =
|
|||
[value] value
|
||||
*[other] {$value_place}
|
||||
} occurs here
|
||||
|
||||
borrowck_opaque_type_non_generic_param =
|
||||
expected generic {$kind} parameter, found `{$ty}`
|
||||
.label = this generic parameter must be used with a generic {$kind} parameter
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
|
|||
infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
|
||||
[true] ...
|
||||
*[false] {""}
|
||||
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
|
||||
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
|
||||
infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
|
||||
[true] ...
|
||||
*[false] {""}
|
||||
|
|
@ -209,7 +209,7 @@ infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
|
|||
infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
|
||||
[true] ...
|
||||
*[false] {""}
|
||||
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`...
|
||||
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
|
||||
infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
|
||||
[true] ...
|
||||
*[false] {""}
|
||||
|
|
@ -225,7 +225,7 @@ infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
|
|||
infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
|
||||
[true] ...
|
||||
*[false] {""}
|
||||
}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
|
||||
}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
|
||||
infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
|
||||
[true] ...
|
||||
*[false] {""}
|
||||
|
|
@ -268,28 +268,28 @@ infer_but_calling_introduces = {$has_param_name ->
|
|||
[true] `{$param_name}`
|
||||
*[false] `fn` parameter
|
||||
} has {$lifetime_kind ->
|
||||
[named] lifetime `{lifetime}`
|
||||
*[anon] an anonymous lifetime `'_`
|
||||
} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement
|
||||
[true] lifetime `{$lifetime}`
|
||||
*[false] an anonymous lifetime `'_`
|
||||
} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement
|
||||
.label1 = {$has_lifetime ->
|
||||
[named] lifetime `{lifetime}`
|
||||
*[anon] an anonymous lifetime `'_`
|
||||
[true] lifetime `{$lifetime}`
|
||||
*[false] an anonymous lifetime `'_`
|
||||
}
|
||||
.label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
|
||||
[named] `impl` of `{$impl_path}`
|
||||
*[anon] inherent `impl`
|
||||
[true] `impl` of `{$impl_path}`
|
||||
*[false] inherent `impl`
|
||||
}
|
||||
|
||||
infer_but_needs_to_satisfy = {$has_param_name ->
|
||||
[true] `{$param_name}`
|
||||
*[false] `fn` parameter
|
||||
} has {$has_lifetime ->
|
||||
[named] lifetime `{lifetime}`
|
||||
*[anon] an anonymous lifetime `'_`
|
||||
[true] lifetime `{$lifetime}`
|
||||
*[false] an anonymous lifetime `'_`
|
||||
} but it needs to satisfy a `'static` lifetime requirement
|
||||
.influencer = this data with {$has_lifetime ->
|
||||
[named] lifetime `{lifetime}`
|
||||
*[anon] an anonymous lifetime `'_`
|
||||
[true] lifetime `{$lifetime}`
|
||||
*[false] an anonymous lifetime `'_`
|
||||
}...
|
||||
.require = {$spans_empty ->
|
||||
*[true] ...is used and required to live as long as `'static` here
|
||||
|
|
@ -302,8 +302,8 @@ infer_more_targeted = {$has_param_name ->
|
|||
[true] `{$param_name}`
|
||||
*[false] `fn` parameter
|
||||
} has {$has_lifetime ->
|
||||
[named] lifetime `{lifetime}`
|
||||
*[anon] an anonymous lifetime `'_`
|
||||
[true] lifetime `{$lifetime}`
|
||||
*[false] an anonymous lifetime `'_`
|
||||
} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
|
||||
|
||||
infer_ril_introduced_here = `'static` requirement introduced here
|
||||
|
|
|
|||
|
|
@ -364,3 +364,5 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
|
|||
[one] variant that isn't
|
||||
*[other] variants that aren't
|
||||
} matched
|
||||
|
||||
mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
|
||||
|
|
|
|||
|
|
@ -10,17 +10,17 @@ ty_utils_address_and_deref_not_supported = dereferencing or taking the address i
|
|||
|
||||
ty_utils_array_not_supported = array construction is not supported in generic constants
|
||||
|
||||
ty_utils_block_not_supported = blocks are not supported in generic constant
|
||||
ty_utils_block_not_supported = blocks are not supported in generic constants
|
||||
|
||||
ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constant
|
||||
ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constants
|
||||
|
||||
ty_utils_tuple_not_supported = tuple construction is not supported in generic constants
|
||||
|
||||
ty_utils_index_not_supported = indexing is not supported in generic constant
|
||||
ty_utils_index_not_supported = indexing is not supported in generic constants
|
||||
|
||||
ty_utils_field_not_supported = field access is not supported in generic constant
|
||||
ty_utils_field_not_supported = field access is not supported in generic constants
|
||||
|
||||
ty_utils_const_block_not_supported = const blocks are not supported in generic constant
|
||||
ty_utils_const_block_not_supported = const blocks are not supported in generic constants
|
||||
|
||||
ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants
|
||||
|
||||
|
|
@ -44,4 +44,4 @@ ty_utils_control_flow_not_supported = control flow is not supported in generic c
|
|||
|
||||
ty_utils_inline_asm_not_supported = assembly is not supported in generic constants
|
||||
|
||||
ty_utils_operation_not_supported = unsupported operation in generic constant
|
||||
ty_utils_operation_not_supported = unsupported operation in generic constants
|
||||
|
|
|
|||
|
|
@ -63,21 +63,21 @@ pub enum Annotatable {
|
|||
|
||||
impl Annotatable {
|
||||
pub fn span(&self) -> Span {
|
||||
match *self {
|
||||
Annotatable::Item(ref item) => item.span,
|
||||
Annotatable::TraitItem(ref trait_item) => trait_item.span,
|
||||
Annotatable::ImplItem(ref impl_item) => impl_item.span,
|
||||
Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
|
||||
Annotatable::Stmt(ref stmt) => stmt.span,
|
||||
Annotatable::Expr(ref expr) => expr.span,
|
||||
Annotatable::Arm(ref arm) => arm.span,
|
||||
Annotatable::ExprField(ref field) => field.span,
|
||||
Annotatable::PatField(ref fp) => fp.pat.span,
|
||||
Annotatable::GenericParam(ref gp) => gp.ident.span,
|
||||
Annotatable::Param(ref p) => p.span,
|
||||
Annotatable::FieldDef(ref sf) => sf.span,
|
||||
Annotatable::Variant(ref v) => v.span,
|
||||
Annotatable::Crate(ref c) => c.spans.inner_span,
|
||||
match self {
|
||||
Annotatable::Item(item) => item.span,
|
||||
Annotatable::TraitItem(trait_item) => trait_item.span,
|
||||
Annotatable::ImplItem(impl_item) => impl_item.span,
|
||||
Annotatable::ForeignItem(foreign_item) => foreign_item.span,
|
||||
Annotatable::Stmt(stmt) => stmt.span,
|
||||
Annotatable::Expr(expr) => expr.span,
|
||||
Annotatable::Arm(arm) => arm.span,
|
||||
Annotatable::ExprField(field) => field.span,
|
||||
Annotatable::PatField(fp) => fp.pat.span,
|
||||
Annotatable::GenericParam(gp) => gp.ident.span,
|
||||
Annotatable::Param(p) => p.span,
|
||||
Annotatable::FieldDef(sf) => sf.span,
|
||||
Annotatable::Variant(v) => v.span,
|
||||
Annotatable::Crate(c) => c.spans.inner_span,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
Some(AttrTokenTree::Delimited(sp, delim, inner))
|
||||
.into_iter()
|
||||
}
|
||||
AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(ref nt) = token.kind => {
|
||||
AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(nt) = &token.kind => {
|
||||
panic!(
|
||||
"Nonterminal should have been flattened at {:?}: {:?}",
|
||||
token.span, nt
|
||||
|
|
|
|||
|
|
@ -144,12 +144,12 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
|
||||
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
|
||||
match *self {
|
||||
AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
|
||||
match self {
|
||||
AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
|
||||
AstFragment::OptExpr(None) => {}
|
||||
AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr),
|
||||
$($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
|
||||
$($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
|
||||
AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
|
||||
$($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
|
||||
$($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
|
||||
visitor.$visit_ast_elt(ast_elt, $($args)*);
|
||||
})?)*
|
||||
}
|
||||
|
|
@ -592,7 +592,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let expn_id = invoc.expansion_data.id;
|
||||
let parent_def = self.cx.resolver.invocation_parent(expn_id);
|
||||
let span = match &mut invoc.kind {
|
||||
InvocationKind::Bang { ref mut span, .. } => span,
|
||||
InvocationKind::Bang { span, .. } => span,
|
||||
InvocationKind::Attr { attr, .. } => &mut attr.span,
|
||||
InvocationKind::Derive { path, .. } => &mut path.span,
|
||||
};
|
||||
|
|
@ -945,8 +945,8 @@ pub fn ensure_complete_parse<'a>(
|
|||
let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root());
|
||||
|
||||
let semi_span = parser.sess.source_map().next_point(span);
|
||||
let add_semicolon = match parser.sess.source_map().span_to_snippet(semi_span) {
|
||||
Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
|
||||
let add_semicolon = match &parser.sess.source_map().span_to_snippet(semi_span) {
|
||||
Ok(snippet) if &snippet[..] != ";" && kind_name == "expression" => {
|
||||
Some(span.shrink_to_hi())
|
||||
}
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -151,9 +151,9 @@ impl<'a, T> Iterator for &'a Stack<'a, T> {
|
|||
|
||||
// Iterates from top to bottom of the stack.
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
match *self {
|
||||
match self {
|
||||
Stack::Empty => None,
|
||||
Stack::Push { ref top, ref prev } => {
|
||||
Stack::Push { top, prev } => {
|
||||
*self = prev;
|
||||
Some(top)
|
||||
}
|
||||
|
|
@ -437,8 +437,8 @@ fn check_nested_occurrences(
|
|||
// We check that the meta-variable is correctly used.
|
||||
check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
|
||||
}
|
||||
(NestedMacroState::MacroRulesNotName, &TokenTree::Delimited(_, ref del))
|
||||
| (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del))
|
||||
(NestedMacroState::MacroRulesNotName, TokenTree::Delimited(_, del))
|
||||
| (NestedMacroState::MacroName, TokenTree::Delimited(_, del))
|
||||
if del.delim == Delimiter::Brace =>
|
||||
{
|
||||
let macro_rules = state == NestedMacroState::MacroRulesNotName;
|
||||
|
|
@ -497,7 +497,7 @@ fn check_nested_occurrences(
|
|||
valid,
|
||||
);
|
||||
}
|
||||
(_, ref tt) => {
|
||||
(_, tt) => {
|
||||
state = NestedMacroState::Empty;
|
||||
check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -486,11 +486,11 @@ pub fn compile_declarative_macro(
|
|||
let mut valid = true;
|
||||
|
||||
// Extract the arguments:
|
||||
let lhses = match argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] {
|
||||
MatchedSeq(ref s) => s
|
||||
let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] {
|
||||
MatchedSeq(s) => s
|
||||
.iter()
|
||||
.map(|m| {
|
||||
if let MatchedTokenTree(ref tt) = *m {
|
||||
if let MatchedTokenTree(tt) = m {
|
||||
let tt = mbe::quoted::parse(
|
||||
TokenStream::new(vec![tt.clone()]),
|
||||
true,
|
||||
|
|
@ -510,11 +510,11 @@ pub fn compile_declarative_macro(
|
|||
_ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
|
||||
};
|
||||
|
||||
let rhses = match argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
|
||||
MatchedSeq(ref s) => s
|
||||
let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
|
||||
MatchedSeq(s) => s
|
||||
.iter()
|
||||
.map(|m| {
|
||||
if let MatchedTokenTree(ref tt) = *m {
|
||||
if let MatchedTokenTree(tt) = m {
|
||||
return mbe::quoted::parse(
|
||||
TokenStream::new(vec![tt.clone()]),
|
||||
false,
|
||||
|
|
@ -624,21 +624,21 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree)
|
|||
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
|
||||
use mbe::TokenTree;
|
||||
for tt in tts {
|
||||
match *tt {
|
||||
match tt {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
| TokenTree::MetaVarExpr(..) => (),
|
||||
TokenTree::Delimited(_, ref del) => {
|
||||
TokenTree::Delimited(_, del) => {
|
||||
if !check_lhs_no_empty_seq(sess, &del.tts) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TokenTree::Sequence(span, ref seq) => {
|
||||
TokenTree::Sequence(span, seq) => {
|
||||
if seq.separator.is_none()
|
||||
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
|
||||
&& seq.tts.iter().all(|seq_tt| match seq_tt {
|
||||
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
|
||||
TokenTree::Sequence(_, ref sub_seq) => {
|
||||
TokenTree::Sequence(_, sub_seq) => {
|
||||
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|
||||
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
|
||||
}
|
||||
|
|
@ -736,21 +736,21 @@ impl<'tt> FirstSets<'tt> {
|
|||
fn build_recur<'tt>(sets: &mut FirstSets<'tt>, tts: &'tt [TokenTree]) -> TokenSet<'tt> {
|
||||
let mut first = TokenSet::empty();
|
||||
for tt in tts.iter().rev() {
|
||||
match *tt {
|
||||
match tt {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
| TokenTree::MetaVarExpr(..) => {
|
||||
first.replace_with(TtHandle::TtRef(tt));
|
||||
}
|
||||
TokenTree::Delimited(span, ref delimited) => {
|
||||
TokenTree::Delimited(span, delimited) => {
|
||||
build_recur(sets, &delimited.tts);
|
||||
first.replace_with(TtHandle::from_token_kind(
|
||||
token::OpenDelim(delimited.delim),
|
||||
span.open,
|
||||
));
|
||||
}
|
||||
TokenTree::Sequence(sp, ref seq_rep) => {
|
||||
TokenTree::Sequence(sp, seq_rep) => {
|
||||
let subfirst = build_recur(sets, &seq_rep.tts);
|
||||
|
||||
match sets.first.entry(sp.entire()) {
|
||||
|
|
@ -804,7 +804,7 @@ impl<'tt> FirstSets<'tt> {
|
|||
let mut first = TokenSet::empty();
|
||||
for tt in tts.iter() {
|
||||
assert!(first.maybe_empty);
|
||||
match *tt {
|
||||
match tt {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
|
|
@ -812,14 +812,14 @@ impl<'tt> FirstSets<'tt> {
|
|||
first.add_one(TtHandle::TtRef(tt));
|
||||
return first;
|
||||
}
|
||||
TokenTree::Delimited(span, ref delimited) => {
|
||||
TokenTree::Delimited(span, delimited) => {
|
||||
first.add_one(TtHandle::from_token_kind(
|
||||
token::OpenDelim(delimited.delim),
|
||||
span.open,
|
||||
));
|
||||
return first;
|
||||
}
|
||||
TokenTree::Sequence(sp, ref seq_rep) => {
|
||||
TokenTree::Sequence(sp, seq_rep) => {
|
||||
let subfirst_owned;
|
||||
let subfirst = match self.first.get(&sp.entire()) {
|
||||
Some(Some(subfirst)) => subfirst,
|
||||
|
|
@ -1041,7 +1041,7 @@ fn check_matcher_core<'tt>(
|
|||
|
||||
// First, update `last` so that it corresponds to the set
|
||||
// of NT tokens that might end the sequence `... token`.
|
||||
match *token {
|
||||
match token {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
|
|
@ -1057,7 +1057,7 @@ fn check_matcher_core<'tt>(
|
|||
suffix_first = build_suffix_first();
|
||||
}
|
||||
}
|
||||
TokenTree::Delimited(span, ref d) => {
|
||||
TokenTree::Delimited(span, d) => {
|
||||
let my_suffix = TokenSet::singleton(TtHandle::from_token_kind(
|
||||
token::CloseDelim(d.delim),
|
||||
span.close,
|
||||
|
|
@ -1070,7 +1070,7 @@ fn check_matcher_core<'tt>(
|
|||
// against SUFFIX
|
||||
continue 'each_token;
|
||||
}
|
||||
TokenTree::Sequence(_, ref seq_rep) => {
|
||||
TokenTree::Sequence(_, seq_rep) => {
|
||||
suffix_first = build_suffix_first();
|
||||
// The trick here: when we check the interior, we want
|
||||
// to include the separator (if any) as a potential
|
||||
|
|
@ -1372,8 +1372,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||
}
|
||||
|
||||
fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
|
||||
match *tt {
|
||||
mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token).into(),
|
||||
match tt {
|
||||
mbe::TokenTree::Token(token) => pprust::token_to_string(&token).into(),
|
||||
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
|
||||
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
|
||||
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ impl<'a> Iterator for Frame<'a> {
|
|||
|
||||
fn next(&mut self) -> Option<&'a mbe::TokenTree> {
|
||||
match self {
|
||||
Frame::Delimited { tts, ref mut idx, .. }
|
||||
| Frame::Sequence { tts, ref mut idx, .. } => {
|
||||
Frame::Delimited { tts, idx, .. } | Frame::Sequence { tts, idx, .. } => {
|
||||
let res = tts.get(*idx);
|
||||
*idx += 1;
|
||||
res
|
||||
|
|
@ -220,13 +219,13 @@ pub(super) fn transcribe<'a>(
|
|||
let ident = MacroRulesNormalizedIdent::new(original_ident);
|
||||
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
||||
match cur_matched {
|
||||
MatchedTokenTree(ref tt) => {
|
||||
MatchedTokenTree(tt) => {
|
||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||
// without wrapping them into groups.
|
||||
let token = tt.clone();
|
||||
result.push(token);
|
||||
}
|
||||
MatchedNonterminal(ref nt) => {
|
||||
MatchedNonterminal(nt) => {
|
||||
// Other variables are emitted into the output stream as groups with
|
||||
// `Delimiter::Invisible` to maintain parsing priorities.
|
||||
// `Interpolated` is currently used for such groups in rustc parser.
|
||||
|
|
@ -299,12 +298,11 @@ fn lookup_cur_matched<'a>(
|
|||
interpolations: &'a FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
||||
repeats: &[(usize, usize)],
|
||||
) -> Option<&'a NamedMatch> {
|
||||
interpolations.get(&ident).map(|matched| {
|
||||
let mut matched = matched;
|
||||
interpolations.get(&ident).map(|mut matched| {
|
||||
for &(idx, _) in repeats {
|
||||
match matched {
|
||||
MatchedTokenTree(_) | MatchedNonterminal(_) => break,
|
||||
MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
|
||||
MatchedSeq(ads) => matched = ads.get(idx).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -339,7 +337,7 @@ impl LockstepIterSize {
|
|||
match self {
|
||||
LockstepIterSize::Unconstrained => other,
|
||||
LockstepIterSize::Contradiction(_) => self,
|
||||
LockstepIterSize::Constraint(l_len, ref l_id) => match other {
|
||||
LockstepIterSize::Constraint(l_len, l_id) => match other {
|
||||
LockstepIterSize::Unconstrained => self,
|
||||
LockstepIterSize::Contradiction(_) => other,
|
||||
LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self,
|
||||
|
|
@ -378,33 +376,33 @@ fn lockstep_iter_size(
|
|||
repeats: &[(usize, usize)],
|
||||
) -> LockstepIterSize {
|
||||
use mbe::TokenTree;
|
||||
match *tree {
|
||||
TokenTree::Delimited(_, ref delimited) => {
|
||||
match tree {
|
||||
TokenTree::Delimited(_, delimited) => {
|
||||
delimited.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
|
||||
size.with(lockstep_iter_size(tt, interpolations, repeats))
|
||||
})
|
||||
}
|
||||
TokenTree::Sequence(_, ref seq) => {
|
||||
TokenTree::Sequence(_, seq) => {
|
||||
seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
|
||||
size.with(lockstep_iter_size(tt, interpolations, repeats))
|
||||
})
|
||||
}
|
||||
TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => {
|
||||
let name = MacroRulesNormalizedIdent::new(name);
|
||||
let name = MacroRulesNormalizedIdent::new(*name);
|
||||
match lookup_cur_matched(name, interpolations, repeats) {
|
||||
Some(matched) => match matched {
|
||||
MatchedTokenTree(_) | MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
|
||||
MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
|
||||
MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name),
|
||||
},
|
||||
_ => LockstepIterSize::Unconstrained,
|
||||
}
|
||||
}
|
||||
TokenTree::MetaVarExpr(_, ref expr) => {
|
||||
TokenTree::MetaVarExpr(_, expr) => {
|
||||
let default_rslt = LockstepIterSize::Unconstrained;
|
||||
let Some(ident) = expr.ident() else { return default_rslt; };
|
||||
let name = MacroRulesNormalizedIdent::new(ident);
|
||||
match lookup_cur_matched(name, interpolations, repeats) {
|
||||
Some(MatchedSeq(ref ads)) => {
|
||||
Some(MatchedSeq(ads)) => {
|
||||
default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
|
||||
}
|
||||
_ => default_rslt,
|
||||
|
|
@ -449,7 +447,7 @@ fn count_repetitions<'a>(
|
|||
Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
|
||||
}
|
||||
}
|
||||
MatchedSeq(ref named_matches) => {
|
||||
MatchedSeq(named_matches) => {
|
||||
let new_declared_lhs_depth = declared_lhs_depth + 1;
|
||||
match depth_opt {
|
||||
None => named_matches
|
||||
|
|
@ -472,7 +470,7 @@ fn count_repetitions<'a>(
|
|||
// before we start counting. `matched` contains the various levels of the
|
||||
// tree as we descend, and its final value is the subtree we are currently at.
|
||||
for &(idx, _) in repeats {
|
||||
if let MatchedSeq(ref ads) = matched {
|
||||
if let MatchedSeq(ads) = matched {
|
||||
matched = &ads[idx];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,9 +176,9 @@ fn get_spans_of_pat_idents(src: &str) -> Vec<Span> {
|
|||
}
|
||||
impl<'a> visit::Visitor<'a> for PatIdentVisitor {
|
||||
fn visit_pat(&mut self, p: &'a ast::Pat) {
|
||||
match p.kind {
|
||||
PatKind::Ident(_, ref ident, _) => {
|
||||
self.spans.push(ident.span.clone());
|
||||
match &p.kind {
|
||||
PatKind::Ident(_, ident, _) => {
|
||||
self.spans.push(ident.span);
|
||||
}
|
||||
_ => {
|
||||
visit::walk_pat(self, p);
|
||||
|
|
@ -290,10 +290,8 @@ fn ttdelim_span() {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let tts: Vec<_> = match expr.kind {
|
||||
ast::ExprKind::MacCall(ref mac) => mac.args.tokens.clone().into_trees().collect(),
|
||||
_ => panic!("not a macro"),
|
||||
};
|
||||
let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") };
|
||||
let tts: Vec<_> = mac.args.tokens.clone().into_trees().collect();
|
||||
|
||||
let span = tts.iter().rev().next().unwrap().span();
|
||||
|
||||
|
|
@ -318,11 +316,8 @@ fn out_of_line_mod() {
|
|||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind {
|
||||
assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
let ast::ItemKind::Mod(_, mod_kind) = &item.kind else { panic!() };
|
||||
assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -597,8 +597,8 @@ impl server::SourceFile for Rustc<'_, '_> {
|
|||
}
|
||||
|
||||
fn path(&mut self, file: &Self::SourceFile) -> String {
|
||||
match file.name {
|
||||
FileName::Real(ref name) => name
|
||||
match &file.name {
|
||||
FileName::Real(name) => name
|
||||
.local_path()
|
||||
.expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
|
||||
.to_str()
|
||||
|
|
|
|||
|
|
@ -1787,6 +1787,14 @@ impl Expr<'_> {
|
|||
expr
|
||||
}
|
||||
|
||||
pub fn peel_borrows(&self) -> &Self {
|
||||
let mut expr = self;
|
||||
while let ExprKind::AddrOf(.., inner) = &expr.kind {
|
||||
expr = inner;
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
||||
pub fn can_have_side_effects(&self) -> bool {
|
||||
match self.peel_drop_temps().kind {
|
||||
ExprKind::Path(_) | ExprKind::Lit(_) => false,
|
||||
|
|
|
|||
|
|
@ -291,6 +291,7 @@ language_item_table! {
|
|||
IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None;
|
||||
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
|
||||
|
||||
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
|
||||
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||
|
||||
FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||
|
|
|
|||
|
|
@ -569,17 +569,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.bindings
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
let kind = match binding.kind {
|
||||
hir::TypeBindingKind::Equality { ref term } => match term {
|
||||
hir::Term::Ty(ref ty) => {
|
||||
let kind = match &binding.kind {
|
||||
hir::TypeBindingKind::Equality { term } => match term {
|
||||
hir::Term::Ty(ty) => {
|
||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
|
||||
}
|
||||
hir::Term::Const(ref c) => {
|
||||
hir::Term::Const(c) => {
|
||||
let c = Const::from_anon_const(self.tcx(), c.def_id);
|
||||
ConvertedBindingKind::Equality(c.into())
|
||||
}
|
||||
},
|
||||
hir::TypeBindingKind::Constraint { ref bounds } => {
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
ConvertedBindingKind::Constraint(bounds)
|
||||
}
|
||||
};
|
||||
|
|
@ -1928,7 +1928,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
let assoc_ident = assoc_segment.ident;
|
||||
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
|
||||
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
|
||||
path.res
|
||||
} else {
|
||||
Res::Err
|
||||
|
|
@ -1971,8 +1971,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
return;
|
||||
};
|
||||
let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
|
||||
hir::QPath::Resolved(_, ref path)
|
||||
) = qself.kind {
|
||||
hir::QPath::Resolved(_, path)
|
||||
) = &qself.kind {
|
||||
// If the path segment already has type params, we want to overwrite
|
||||
// them.
|
||||
match &path.segments[..] {
|
||||
|
|
@ -2602,7 +2602,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
match path.res {
|
||||
Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => {
|
||||
// Check for desugared `impl Trait`.
|
||||
assert!(ty::is_impl_trait_defn(tcx, did).is_none());
|
||||
assert!(tcx.is_type_alias_impl_trait(did));
|
||||
let item_segment = path.segments.split_last().unwrap();
|
||||
self.prohibit_generics(item_segment.1.iter(), |err| {
|
||||
err.note("`impl Trait` types can't have type parameters");
|
||||
|
|
@ -2760,7 +2760,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
"generic `Self` types are currently not permitted in anonymous constants",
|
||||
);
|
||||
if let Some(hir::Node::Item(&hir::Item {
|
||||
kind: hir::ItemKind::Impl(ref impl_),
|
||||
kind: hir::ItemKind::Impl(impl_),
|
||||
..
|
||||
})) = tcx.hir().get_if_local(def_id)
|
||||
{
|
||||
|
|
@ -2843,12 +2843,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let result_ty = match ast_ty.kind {
|
||||
hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
|
||||
hir::TyKind::Ptr(ref mt) => {
|
||||
let result_ty = match &ast_ty.kind {
|
||||
hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
|
||||
hir::TyKind::Ptr(mt) => {
|
||||
tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
|
||||
}
|
||||
hir::TyKind::Ref(ref region, ref mt) => {
|
||||
hir::TyKind::Ref(region, mt) => {
|
||||
let r = self.ast_region_to_region(region, None);
|
||||
debug!(?r);
|
||||
let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
|
||||
|
|
@ -2868,7 +2868,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
Some(ast_ty),
|
||||
))
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, ref lifetime, repr) => {
|
||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||
self.maybe_lint_bare_trait(ast_ty, in_path);
|
||||
let repr = match repr {
|
||||
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
|
||||
|
|
@ -2876,12 +2876,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
};
|
||||
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
|
||||
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
|
||||
self.res_to_ty(opt_self_ty, path, false)
|
||||
}
|
||||
hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
|
||||
&hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
|
||||
let opaque_ty = tcx.hir().item(item_id);
|
||||
let def_id = item_id.owner_id.to_def_id();
|
||||
|
||||
|
|
@ -2892,14 +2892,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
||||
}
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
|
||||
debug!(?qself, ?segment);
|
||||
let ty = self.ast_ty_to_ty_inner(qself, false, true);
|
||||
self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
|
||||
.map(|(ty, _, _)| ty)
|
||||
.unwrap_or_else(|_| tcx.ty_error())
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
|
||||
&hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
|
||||
let def_id = tcx.require_lang_item(lang_item, Some(span));
|
||||
let (substs, _) = self.create_substs_for_ast_path(
|
||||
span,
|
||||
|
|
@ -2913,7 +2913,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
);
|
||||
EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs)
|
||||
}
|
||||
hir::TyKind::Array(ref ty, ref length) => {
|
||||
hir::TyKind::Array(ty, length) => {
|
||||
let length = match length {
|
||||
&hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
|
||||
hir::ArrayLen::Body(constant) => {
|
||||
|
|
@ -2923,7 +2923,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length))
|
||||
}
|
||||
hir::TyKind::Typeof(ref e) => {
|
||||
hir::TyKind::Typeof(e) => {
|
||||
let ty_erased = tcx.type_of(e.def_id);
|
||||
let ty = tcx.fold_regions(ty_erased, |r, _| {
|
||||
if r.is_erased() { tcx.lifetimes.re_static } else { r }
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
|||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!(?t, "root_visit_ty");
|
||||
if t == self.opaque_identity_ty {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||
tcx: self.tcx,
|
||||
|
|
@ -282,7 +282,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
|||
if self.references_parent_regions {
|
||||
ControlFlow::Break(t)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -531,9 +531,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
DefKind::Fn => {} // entirely within check_item_body
|
||||
DefKind::Impl => {
|
||||
let it = tcx.hir().item(id);
|
||||
let hir::ItemKind::Impl(ref impl_) = it.kind else {
|
||||
return;
|
||||
};
|
||||
let hir::ItemKind::Impl(impl_) = it.kind else { return };
|
||||
debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
|
||||
if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
|
||||
check_impl_items_against_trait(
|
||||
|
|
@ -548,15 +546,15 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
}
|
||||
DefKind::Trait => {
|
||||
let it = tcx.hir().item(id);
|
||||
let hir::ItemKind::Trait(_, _, _, _, ref items) = it.kind else {
|
||||
let hir::ItemKind::Trait(_, _, _, _, items) = it.kind else {
|
||||
return;
|
||||
};
|
||||
check_on_unimplemented(tcx, it);
|
||||
|
||||
for item in items.iter() {
|
||||
let item = tcx.hir().trait_item(item.id);
|
||||
match item.kind {
|
||||
hir::TraitItemKind::Fn(ref sig, _) => {
|
||||
match &item.kind {
|
||||
hir::TraitItemKind::Fn(sig, _) => {
|
||||
let abi = sig.header.abi;
|
||||
fn_maybe_err(tcx, item.ident.span, abi);
|
||||
}
|
||||
|
|
@ -652,8 +650,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
}
|
||||
|
||||
let item = tcx.hir().foreign_item(item.id);
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(ref fn_decl, _, _) => {
|
||||
match &item.kind {
|
||||
hir::ForeignItemKind::Fn(fn_decl, _, _) => {
|
||||
require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
|
||||
}
|
||||
hir::ForeignItemKind::Static(..) => {
|
||||
|
|
@ -1393,11 +1391,15 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed
|
|||
///
|
||||
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
|
||||
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
|
||||
fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed {
|
||||
fn opaque_type_cycle_error(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_def_id: LocalDefId,
|
||||
span: Span,
|
||||
) -> ErrorGuaranteed {
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
|
||||
|
||||
let mut label = false;
|
||||
if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
|
||||
if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
|
||||
let typeck_results = tcx.typeck(def_id);
|
||||
if visitor
|
||||
.returns
|
||||
|
|
@ -1433,21 +1435,30 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
|
|||
.filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
|
||||
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
|
||||
{
|
||||
struct OpaqueTypeCollector(Vec<DefId>);
|
||||
#[derive(Default)]
|
||||
struct OpaqueTypeCollector {
|
||||
opaques: Vec<DefId>,
|
||||
closures: Vec<DefId>,
|
||||
}
|
||||
impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match *t.kind() {
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
||||
self.0.push(def);
|
||||
ControlFlow::CONTINUE
|
||||
self.opaques.push(def);
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
|
||||
self.closures.push(def_id);
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut visitor = OpaqueTypeCollector(vec![]);
|
||||
|
||||
let mut visitor = OpaqueTypeCollector::default();
|
||||
ty.visit_with(&mut visitor);
|
||||
for def_id in visitor.0 {
|
||||
for def_id in visitor.opaques {
|
||||
let ty_span = tcx.def_span(def_id);
|
||||
if !seen.contains(&ty_span) {
|
||||
err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
|
||||
|
|
@ -1455,6 +1466,40 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
|
|||
}
|
||||
err.span_label(sp, &format!("returning here with type `{ty}`"));
|
||||
}
|
||||
|
||||
for closure_def_id in visitor.closures {
|
||||
let Some(closure_local_did) = closure_def_id.as_local() else { continue; };
|
||||
let typeck_results = tcx.typeck(closure_local_did);
|
||||
|
||||
let mut label_match = |ty: Ty<'_>, span| {
|
||||
for arg in ty.walk() {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
|
||||
&& captured_def_id == opaque_def_id.to_def_id()
|
||||
{
|
||||
err.span_label(
|
||||
span,
|
||||
format!(
|
||||
"{} captures itself here",
|
||||
tcx.def_kind(closure_def_id).descr(closure_def_id)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Label any closure upvars that capture the opaque
|
||||
for capture in typeck_results.closure_min_captures_flattened(closure_local_did)
|
||||
{
|
||||
label_match(capture.place.ty(), capture.get_path_span(tcx));
|
||||
}
|
||||
// Label any generator locals that capture the opaque
|
||||
for interior_ty in
|
||||
typeck_results.generator_interior_types.as_ref().skip_binder()
|
||||
{
|
||||
label_match(interior_ty.ty, interior_ty.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,42 +47,22 @@ pub(super) fn compare_impl_method<'tcx>(
|
|||
|
||||
let impl_m_span = tcx.def_span(impl_m.def_id);
|
||||
|
||||
if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(_) =
|
||||
compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(_) = compare_method_predicate_entailment(
|
||||
tcx,
|
||||
impl_m,
|
||||
impl_m_span,
|
||||
trait_m,
|
||||
impl_trait_ref,
|
||||
CheckImpliedWfMode::Check,
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let _: Result<_, ErrorGuaranteed> = try {
|
||||
compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)?;
|
||||
compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false)?;
|
||||
compare_generic_param_kinds(tcx, impl_m, trait_m, false)?;
|
||||
compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
|
||||
compare_synthetic_generics(tcx, impl_m, trait_m)?;
|
||||
compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
|
||||
compare_method_predicate_entailment(
|
||||
tcx,
|
||||
impl_m,
|
||||
impl_m_span,
|
||||
trait_m,
|
||||
impl_trait_ref,
|
||||
CheckImpliedWfMode::Check,
|
||||
)?;
|
||||
};
|
||||
}
|
||||
|
||||
/// This function is best explained by example. Consider a trait:
|
||||
|
|
@ -209,9 +189,11 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
//
|
||||
// We then register the obligations from the impl_m and check to see
|
||||
// if all constraints hold.
|
||||
hybrid_preds
|
||||
.predicates
|
||||
.extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
|
||||
hybrid_preds.predicates.extend(
|
||||
trait_m_predicates
|
||||
.instantiate_own(tcx, trait_to_placeholder_substs)
|
||||
.map(|(predicate, _)| predicate),
|
||||
);
|
||||
|
||||
// Construct trait parameter environment and then shift it into the placeholder viewpoint.
|
||||
// The key step here is to update the caller_bounds's predicates to be
|
||||
|
|
@ -230,7 +212,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
|
||||
|
||||
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
|
||||
for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
|
||||
for (predicate, span) in impl_m_own_bounds {
|
||||
let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
|
||||
let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
|
||||
|
||||
|
|
@ -934,16 +916,14 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
|
||||
// span points only at the type `Box<Self`>, but we want to cover the whole
|
||||
// argument pattern and type.
|
||||
let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
|
||||
ImplItemKind::Fn(ref sig, body) => tcx
|
||||
.hir()
|
||||
.body_param_names(body)
|
||||
.zip(sig.decl.inputs.iter())
|
||||
.map(|(param, ty)| param.span.to(ty.span))
|
||||
.next()
|
||||
.unwrap_or(impl_err_span),
|
||||
_ => bug!("{:?} is not a method", impl_m),
|
||||
};
|
||||
let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") };
|
||||
let span = tcx
|
||||
.hir()
|
||||
.body_param_names(body)
|
||||
.zip(sig.decl.inputs.iter())
|
||||
.map(|(param, ty)| param.span.to(ty.span))
|
||||
.next()
|
||||
.unwrap_or(impl_err_span);
|
||||
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
|
|
@ -956,22 +936,21 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
if trait_sig.inputs().len() == *i {
|
||||
// Suggestion to change output type. We do not suggest in `async` functions
|
||||
// to avoid complex logic or incorrect output.
|
||||
match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
|
||||
ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
|
||||
let msg = "change the output type to match the trait";
|
||||
let ap = Applicability::MachineApplicable;
|
||||
match sig.decl.output {
|
||||
hir::FnRetTy::DefaultReturn(sp) => {
|
||||
let sugg = format!("-> {} ", trait_sig.output());
|
||||
diag.span_suggestion_verbose(sp, msg, sugg, ap);
|
||||
}
|
||||
hir::FnRetTy::Return(hir_ty) => {
|
||||
let sugg = trait_sig.output();
|
||||
diag.span_suggestion(hir_ty.span, msg, sugg, ap);
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
|
||||
&& !sig.header.asyncness.is_async()
|
||||
{
|
||||
let msg = "change the output type to match the trait";
|
||||
let ap = Applicability::MachineApplicable;
|
||||
match sig.decl.output {
|
||||
hir::FnRetTy::DefaultReturn(sp) => {
|
||||
let sugg = format!("-> {} ", trait_sig.output());
|
||||
diag.span_suggestion_verbose(sp, msg, sugg, ap);
|
||||
}
|
||||
hir::FnRetTy::Return(hir_ty) => {
|
||||
let sugg = trait_sig.output();
|
||||
diag.span_suggestion(hir_ty.span, msg, sugg, ap);
|
||||
}
|
||||
};
|
||||
};
|
||||
} else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
|
||||
diag.span_suggestion(
|
||||
|
|
@ -1098,25 +1077,18 @@ fn extract_spans_for_error_reporting<'tcx>(
|
|||
trait_m: &ty::AssocItem,
|
||||
) -> (Span, Option<Span>) {
|
||||
let tcx = infcx.tcx;
|
||||
let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
|
||||
ImplItemKind::Fn(ref sig, _) => {
|
||||
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
|
||||
}
|
||||
_ => bug!("{:?} is not a method", impl_m),
|
||||
let mut impl_args = {
|
||||
let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
|
||||
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
|
||||
};
|
||||
let trait_args =
|
||||
trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
|
||||
TraitItemKind::Fn(ref sig, _) => {
|
||||
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
|
||||
}
|
||||
_ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
|
||||
});
|
||||
|
||||
let trait_args = trait_m.def_id.as_local().map(|def_id| {
|
||||
let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) };
|
||||
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
|
||||
});
|
||||
|
||||
match terr {
|
||||
TypeError::ArgumentMutability(i) => {
|
||||
(impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
|
||||
}
|
||||
TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
|
||||
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
|
||||
(impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
|
||||
}
|
||||
_ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
|
||||
|
|
@ -1176,8 +1148,7 @@ fn compare_self_type<'tcx>(
|
|||
} else {
|
||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
||||
}
|
||||
let reported = err.emit();
|
||||
return Err(reported);
|
||||
return Err(err.emit());
|
||||
}
|
||||
|
||||
(true, false) => {
|
||||
|
|
@ -1196,8 +1167,8 @@ fn compare_self_type<'tcx>(
|
|||
} else {
|
||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
||||
}
|
||||
let reported = err.emit();
|
||||
return Err(reported);
|
||||
|
||||
return Err(err.emit());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1379,41 +1350,39 @@ fn compare_number_of_method_arguments<'tcx>(
|
|||
let trait_m_fty = tcx.fn_sig(trait_m.def_id);
|
||||
let trait_number_args = trait_m_fty.inputs().skip_binder().len();
|
||||
let impl_number_args = impl_m_fty.inputs().skip_binder().len();
|
||||
|
||||
if trait_number_args != impl_number_args {
|
||||
let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
|
||||
match tcx.hir().expect_trait_item(def_id).kind {
|
||||
TraitItemKind::Fn(ref trait_m_sig, _) => {
|
||||
let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
|
||||
if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
|
||||
Some(if pos == 0 {
|
||||
arg.span
|
||||
} else {
|
||||
arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
|
||||
})
|
||||
} else {
|
||||
trait_item_span
|
||||
}
|
||||
}
|
||||
_ => bug!("{:?} is not a method", impl_m),
|
||||
}
|
||||
} else {
|
||||
trait_item_span
|
||||
};
|
||||
let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
|
||||
ImplItemKind::Fn(ref impl_m_sig, _) => {
|
||||
let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
|
||||
if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
|
||||
let trait_span = trait_m
|
||||
.def_id
|
||||
.as_local()
|
||||
.and_then(|def_id| {
|
||||
let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) };
|
||||
let pos = trait_number_args.saturating_sub(1);
|
||||
trait_m_sig.decl.inputs.get(pos).map(|arg| {
|
||||
if pos == 0 {
|
||||
arg.span
|
||||
} else {
|
||||
arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
|
||||
arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
|
||||
}
|
||||
})
|
||||
})
|
||||
.or(trait_item_span);
|
||||
|
||||
let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
|
||||
let pos = impl_number_args.saturating_sub(1);
|
||||
let impl_span = impl_m_sig
|
||||
.decl
|
||||
.inputs
|
||||
.get(pos)
|
||||
.map(|arg| {
|
||||
if pos == 0 {
|
||||
arg.span
|
||||
} else {
|
||||
impl_m_span
|
||||
arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
|
||||
}
|
||||
}
|
||||
_ => bug!("{:?} is not a method", impl_m),
|
||||
};
|
||||
})
|
||||
.unwrap_or(impl_m_span);
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
impl_span,
|
||||
|
|
@ -1424,6 +1393,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
|||
tcx.def_path_str(trait_m.def_id),
|
||||
trait_number_args
|
||||
);
|
||||
|
||||
if let Some(trait_span) = trait_span {
|
||||
err.span_label(
|
||||
trait_span,
|
||||
|
|
@ -1435,6 +1405,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
|||
} else {
|
||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
||||
}
|
||||
|
||||
err.span_label(
|
||||
impl_span,
|
||||
format!(
|
||||
|
|
@ -1443,8 +1414,8 @@ fn compare_number_of_method_arguments<'tcx>(
|
|||
impl_number_args
|
||||
),
|
||||
);
|
||||
let reported = err.emit();
|
||||
return Err(reported);
|
||||
|
||||
return Err(err.emit());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -1491,7 +1462,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||
// explicit generics
|
||||
(true, false) => {
|
||||
err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
|
||||
(|| {
|
||||
let _: Option<_> = try {
|
||||
// try taking the name from the trait impl
|
||||
// FIXME: this is obviously suboptimal since the name can already be used
|
||||
// as another generic argument
|
||||
|
|
@ -1524,26 +1495,23 @@ fn compare_synthetic_generics<'tcx>(
|
|||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
Some(())
|
||||
})();
|
||||
};
|
||||
}
|
||||
// The case where the trait method uses `impl Trait`, but the impl method uses
|
||||
// explicit generics.
|
||||
(false, true) => {
|
||||
err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
|
||||
(|| {
|
||||
let _: Option<_> = try {
|
||||
let impl_m = impl_m.def_id.as_local()?;
|
||||
let impl_m = tcx.hir().expect_impl_item(impl_m);
|
||||
let input_tys = match impl_m.kind {
|
||||
hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() };
|
||||
let input_tys = sig.decl.inputs;
|
||||
|
||||
struct Visitor(Option<Span>, hir::def_id::LocalDefId);
|
||||
impl<'v> intravisit::Visitor<'v> for Visitor {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||
intravisit::walk_ty(self, ty);
|
||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
|
||||
ty.kind
|
||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
|
||||
&& let Res::Def(DefKind::TyParam, def_id) = path.res
|
||||
&& def_id == self.1.to_def_id()
|
||||
{
|
||||
|
|
@ -1551,6 +1519,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = Visitor(None, impl_def_id);
|
||||
for ty in input_tys {
|
||||
intravisit::Visitor::visit_ty(&mut visitor, ty);
|
||||
|
|
@ -1571,13 +1540,11 @@ fn compare_synthetic_generics<'tcx>(
|
|||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
Some(())
|
||||
})();
|
||||
};
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let reported = err.emit();
|
||||
error_found = Some(reported);
|
||||
error_found = Some(err.emit());
|
||||
}
|
||||
}
|
||||
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
|
||||
|
|
@ -1737,10 +1704,8 @@ pub(super) fn compare_impl_const_raw(
|
|||
);
|
||||
|
||||
// Locate the Span containing just the type of the offending impl
|
||||
match tcx.hir().expect_impl_item(impl_const_item_def).kind {
|
||||
ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
|
||||
_ => bug!("{:?} is not a impl const", impl_const_item),
|
||||
}
|
||||
let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") };
|
||||
cause.span = ty.span;
|
||||
|
||||
let mut diag = struct_span_err!(
|
||||
tcx.sess,
|
||||
|
|
@ -1752,10 +1717,8 @@ pub(super) fn compare_impl_const_raw(
|
|||
|
||||
let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
|
||||
// Add a label to the Span containing just the type of the const
|
||||
match tcx.hir().expect_trait_item(trait_c_def_id).kind {
|
||||
TraitItemKind::Const(ref ty, _) => ty.span,
|
||||
_ => bug!("{:?} is not a trait const", trait_const_item),
|
||||
}
|
||||
let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") };
|
||||
ty.span
|
||||
});
|
||||
|
||||
infcx.err_ctxt().note_type_err(
|
||||
|
|
@ -1797,7 +1760,7 @@ pub(super) fn compare_impl_ty<'tcx>(
|
|||
) {
|
||||
debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
|
||||
|
||||
let _: Result<(), ErrorGuaranteed> = (|| {
|
||||
let _: Result<(), ErrorGuaranteed> = try {
|
||||
compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
|
||||
|
||||
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
|
||||
|
|
@ -1805,8 +1768,8 @@ pub(super) fn compare_impl_ty<'tcx>(
|
|||
let sp = tcx.def_span(impl_ty.def_id);
|
||||
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
|
||||
|
||||
check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
|
||||
})();
|
||||
check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)?;
|
||||
};
|
||||
}
|
||||
|
||||
/// The equivalent of [compare_method_predicate_entailment], but for associated types
|
||||
|
|
@ -1828,8 +1791,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
|
||||
|
||||
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
|
||||
|
||||
if impl_ty_own_bounds.is_empty() {
|
||||
if impl_ty_own_bounds.len() == 0 {
|
||||
// Nothing to check.
|
||||
return Ok(());
|
||||
}
|
||||
|
|
@ -1844,9 +1806,11 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
// associated type in the trait are assumed.
|
||||
let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
|
||||
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
|
||||
hybrid_preds
|
||||
.predicates
|
||||
.extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
|
||||
hybrid_preds.predicates.extend(
|
||||
trait_ty_predicates
|
||||
.instantiate_own(tcx, trait_to_impl_substs)
|
||||
.map(|(predicate, _)| predicate),
|
||||
);
|
||||
|
||||
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
|
||||
|
||||
|
|
@ -1862,9 +1826,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
|
||||
debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
|
||||
|
||||
assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
|
||||
for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
|
||||
{
|
||||
for (predicate, span) in impl_ty_own_bounds {
|
||||
let cause = ObligationCause::misc(span, impl_ty_hir_id);
|
||||
let predicate = ocx.normalize(&cause, param_env, predicate);
|
||||
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
match *op {
|
||||
hir::InlineAsmOperand::In { reg, ref expr } => {
|
||||
hir::InlineAsmOperand::In { reg, expr } => {
|
||||
self.check_asm_operand_type(
|
||||
idx,
|
||||
reg,
|
||||
|
|
@ -362,7 +362,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
&target_features,
|
||||
);
|
||||
}
|
||||
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
|
||||
hir::InlineAsmOperand::Out { reg, late: _, expr } => {
|
||||
if let Some(expr) = expr {
|
||||
self.check_asm_operand_type(
|
||||
idx,
|
||||
|
|
@ -375,7 +375,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => {
|
||||
hir::InlineAsmOperand::InOut { reg, late: _, expr } => {
|
||||
self.check_asm_operand_type(
|
||||
idx,
|
||||
reg,
|
||||
|
|
@ -386,7 +386,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
&target_features,
|
||||
);
|
||||
}
|
||||
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
|
||||
hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => {
|
||||
let in_ty = self.check_asm_operand_type(
|
||||
idx,
|
||||
reg,
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir
|
|||
|
||||
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
|
||||
|
||||
if let Some(hir::Guard::If(ref expr)) = arm.guard {
|
||||
if let Some(hir::Guard::If(expr)) = arm.guard {
|
||||
visitor.terminating_scopes.insert(expr.hir_id.local_id);
|
||||
}
|
||||
|
||||
|
|
@ -242,8 +242,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
// This ensures fixed size stacks.
|
||||
hir::ExprKind::Binary(
|
||||
source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
|
||||
ref l,
|
||||
ref r,
|
||||
l,
|
||||
r,
|
||||
) => {
|
||||
// expr is a short circuiting operator (|| or &&). As its
|
||||
// functionality can't be overridden by traits, it always
|
||||
|
|
@ -288,20 +288,20 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
terminating(r.hir_id.local_id);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
|
||||
hir::ExprKind::If(_, then, Some(otherwise)) => {
|
||||
terminating(then.hir_id.local_id);
|
||||
terminating(otherwise.hir_id.local_id);
|
||||
}
|
||||
|
||||
hir::ExprKind::If(_, ref then, None) => {
|
||||
hir::ExprKind::If(_, then, None) => {
|
||||
terminating(then.hir_id.local_id);
|
||||
}
|
||||
|
||||
hir::ExprKind::Loop(ref body, _, _, _) => {
|
||||
hir::ExprKind::Loop(body, _, _, _) => {
|
||||
terminating(body.hir_id.local_id);
|
||||
}
|
||||
|
||||
hir::ExprKind::DropTemps(ref expr) => {
|
||||
hir::ExprKind::DropTemps(expr) => {
|
||||
// `DropTemps(expr)` does not denote a conditional scope.
|
||||
// Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
|
||||
terminating(expr.hir_id.local_id);
|
||||
|
|
@ -396,7 +396,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
let body = visitor.tcx.hir().body(body);
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
hir::ExprKind::AssignOp(_, ref left_expr, ref right_expr) => {
|
||||
hir::ExprKind::AssignOp(_, left_expr, right_expr) => {
|
||||
debug!(
|
||||
"resolve_expr - enabling pessimistic_yield, was previously {}",
|
||||
prev_pessimistic
|
||||
|
|
@ -447,7 +447,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
|
||||
hir::ExprKind::If(cond, then, Some(otherwise)) => {
|
||||
let expr_cx = visitor.cx;
|
||||
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
|
|
@ -457,7 +457,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
visitor.visit_expr(otherwise);
|
||||
}
|
||||
|
||||
hir::ExprKind::If(ref cond, ref then, None) => {
|
||||
hir::ExprKind::If(cond, then, None) => {
|
||||
let expr_cx = visitor.cx;
|
||||
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
|
|
@ -641,21 +641,21 @@ fn resolve_local<'tcx>(
|
|||
match pat.kind {
|
||||
PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
|
||||
|
||||
PatKind::Struct(_, ref field_pats, _) => {
|
||||
PatKind::Struct(_, field_pats, _) => {
|
||||
field_pats.iter().any(|fp| is_binding_pat(&fp.pat))
|
||||
}
|
||||
|
||||
PatKind::Slice(ref pats1, ref pats2, ref pats3) => {
|
||||
PatKind::Slice(pats1, pats2, pats3) => {
|
||||
pats1.iter().any(|p| is_binding_pat(&p))
|
||||
|| pats2.iter().any(|p| is_binding_pat(&p))
|
||||
|| pats3.iter().any(|p| is_binding_pat(&p))
|
||||
}
|
||||
|
||||
PatKind::Or(ref subpats)
|
||||
| PatKind::TupleStruct(_, ref subpats, _)
|
||||
| PatKind::Tuple(ref subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)),
|
||||
PatKind::Or(subpats)
|
||||
| PatKind::TupleStruct(_, subpats, _)
|
||||
| PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)),
|
||||
|
||||
PatKind::Box(ref subpat) => is_binding_pat(&subpat),
|
||||
PatKind::Box(subpat) => is_binding_pat(&subpat),
|
||||
|
||||
PatKind::Ref(_, _)
|
||||
| PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
|
||||
|
|
@ -704,11 +704,11 @@ fn resolve_local<'tcx>(
|
|||
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Cast(ref subexpr, _) => {
|
||||
hir::ExprKind::Cast(subexpr, _) => {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id)
|
||||
}
|
||||
hir::ExprKind::Block(ref block, _) => {
|
||||
if let Some(ref subexpr) = block.expr {
|
||||
hir::ExprKind::Block(block, _) => {
|
||||
if let Some(subexpr) = block.expr {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ use rustc_trait_selection::traits::{
|
|||
};
|
||||
|
||||
use std::cell::LazyCell;
|
||||
use std::iter;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
pub(super) struct WfCheckingCtxt<'a, 'tcx> {
|
||||
|
|
@ -179,7 +178,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
|||
//
|
||||
// won't be allowed unless there's an *explicit* implementation of `Send`
|
||||
// for `T`
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
let is_auto = tcx
|
||||
.impl_trait_ref(def_id)
|
||||
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
|
||||
|
|
@ -225,15 +224,15 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
|||
hir::ItemKind::Const(ty, ..) => {
|
||||
check_item_type(tcx, def_id, ty.span, false);
|
||||
}
|
||||
hir::ItemKind::Struct(_, ref ast_generics) => {
|
||||
hir::ItemKind::Struct(_, ast_generics) => {
|
||||
check_type_defn(tcx, item, false);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
hir::ItemKind::Union(_, ref ast_generics) => {
|
||||
hir::ItemKind::Union(_, ast_generics) => {
|
||||
check_type_defn(tcx, item, true);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
hir::ItemKind::Enum(_, ref ast_generics) => {
|
||||
hir::ItemKind::Enum(_, ast_generics) => {
|
||||
check_type_defn(tcx, item, true);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
|
|
@ -1248,8 +1247,8 @@ fn check_impl<'tcx>(
|
|||
constness: hir::Constness,
|
||||
) {
|
||||
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
|
||||
match *ast_trait_ref {
|
||||
Some(ref ast_trait_ref) => {
|
||||
match ast_trait_ref {
|
||||
Some(ast_trait_ref) => {
|
||||
// `#[rustc_reservation_impl]` impls are not real impls and
|
||||
// therefore don't need to be WF (the trait's `Self: Trait` predicate
|
||||
// won't hold).
|
||||
|
|
@ -1310,7 +1309,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
let infcx = wfcx.infcx;
|
||||
let tcx = wfcx.tcx();
|
||||
|
||||
let predicates = tcx.bound_predicates_of(def_id.to_def_id());
|
||||
let predicates = tcx.predicates_of(def_id.to_def_id());
|
||||
let generics = tcx.generics_of(def_id);
|
||||
|
||||
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
|
||||
|
|
@ -1411,7 +1410,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
|
||||
// Now we build the substituted predicates.
|
||||
let default_obligations = predicates
|
||||
.0
|
||||
.predicates
|
||||
.iter()
|
||||
.flat_map(|&(pred, sp)| {
|
||||
|
|
@ -1430,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
}
|
||||
|
||||
fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
|
|
@ -1442,13 +1440,13 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
}
|
||||
let mut param_count = CountParams::default();
|
||||
let has_region = pred.visit_with(&mut param_count).is_break();
|
||||
let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
|
||||
let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs);
|
||||
// Don't check non-defaulted params, dependent defaults (including lifetimes)
|
||||
// or preds with multiple params.
|
||||
if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
|
||||
{
|
||||
None
|
||||
} else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
|
||||
} else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
|
||||
// Avoid duplication of predicates that contain no parameters, for example.
|
||||
None
|
||||
} else {
|
||||
|
|
@ -1474,22 +1472,21 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
|
||||
});
|
||||
|
||||
let predicates = predicates.0.instantiate_identity(tcx);
|
||||
let predicates = predicates.instantiate_identity(tcx);
|
||||
|
||||
let predicates = wfcx.normalize(span, None, predicates);
|
||||
|
||||
debug!(?predicates.predicates);
|
||||
assert_eq!(predicates.predicates.len(), predicates.spans.len());
|
||||
let wf_obligations =
|
||||
iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
|
||||
traits::wf::predicate_obligations(
|
||||
infcx,
|
||||
wfcx.param_env.without_const(),
|
||||
wfcx.body_id,
|
||||
p,
|
||||
sp,
|
||||
)
|
||||
});
|
||||
let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
|
||||
traits::wf::predicate_obligations(
|
||||
infcx,
|
||||
wfcx.param_env.without_const(),
|
||||
wfcx.body_id,
|
||||
p,
|
||||
sp,
|
||||
)
|
||||
});
|
||||
|
||||
let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
|
||||
wfcx.register_obligations(obligations);
|
||||
|
|
|
|||
|
|
@ -7,13 +7,15 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::ItemKind;
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::{self, RegionResolutionError};
|
||||
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
|
||||
use rustc_trait_selection::traits::misc::{
|
||||
type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
|
||||
};
|
||||
use rustc_trait_selection::traits::predicate_for_trait_def;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||
use std::collections::BTreeMap;
|
||||
|
|
@ -54,12 +56,9 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
let sp = match tcx.hir().expect_item(impl_did).kind {
|
||||
ItemKind::Impl(ref impl_) => impl_.self_ty.span,
|
||||
_ => bug!("expected Drop impl item"),
|
||||
};
|
||||
let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") };
|
||||
|
||||
tcx.sess.emit_err(DropImplOnWrongItem { span: sp });
|
||||
tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span });
|
||||
}
|
||||
|
||||
fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
||||
|
|
@ -82,7 +81,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
|||
};
|
||||
|
||||
let cause = traits::ObligationCause::misc(span, impl_hir_id);
|
||||
match can_type_implement_copy(tcx, param_env, self_type, cause) {
|
||||
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
|
||||
Ok(()) => {}
|
||||
Err(CopyImplementationError::InfrigingFields(fields)) => {
|
||||
let mut err = struct_span_err!(
|
||||
|
|
@ -97,50 +96,70 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
|||
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
|
||||
let mut bounds = vec![];
|
||||
|
||||
for (field, ty) in fields {
|
||||
for (field, ty, reason) in fields {
|
||||
let field_span = tcx.def_span(field.did);
|
||||
let field_ty_span = match tcx.hir().get_if_local(field.did) {
|
||||
Some(hir::Node::Field(field_def)) => field_def.ty.span,
|
||||
_ => field_span,
|
||||
};
|
||||
err.span_label(field_span, "this field does not implement `Copy`");
|
||||
// Spin up a new FulfillmentContext, so we can get the _precise_ reason
|
||||
// why this field does not implement Copy. This is useful because sometimes
|
||||
// it is not immediately clear why Copy is not implemented for a field, since
|
||||
// all we point at is the field itself.
|
||||
let infcx = tcx.infer_ctxt().ignoring_regions().build();
|
||||
for error in traits::fully_solve_bound(
|
||||
&infcx,
|
||||
traits::ObligationCause::dummy_with_span(field_ty_span),
|
||||
param_env,
|
||||
ty,
|
||||
tcx.require_lang_item(LangItem::Copy, Some(span)),
|
||||
) {
|
||||
let error_predicate = error.obligation.predicate;
|
||||
// Only note if it's not the root obligation, otherwise it's trivial and
|
||||
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
|
||||
|
||||
// FIXME: This error could be more descriptive, especially if the error_predicate
|
||||
// contains a foreign type or if it's a deeply nested type...
|
||||
if error_predicate != error.root_obligation.predicate {
|
||||
errors
|
||||
.entry((ty.to_string(), error_predicate.to_string()))
|
||||
.or_default()
|
||||
.push(error.obligation.cause.span);
|
||||
match reason {
|
||||
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
|
||||
for error in fulfillment_errors {
|
||||
let error_predicate = error.obligation.predicate;
|
||||
// Only note if it's not the root obligation, otherwise it's trivial and
|
||||
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
|
||||
|
||||
// FIXME: This error could be more descriptive, especially if the error_predicate
|
||||
// contains a foreign type or if it's a deeply nested type...
|
||||
if error_predicate != error.root_obligation.predicate {
|
||||
errors
|
||||
.entry((ty.to_string(), error_predicate.to_string()))
|
||||
.or_default()
|
||||
.push(error.obligation.cause.span);
|
||||
}
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(
|
||||
ty::TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
..
|
||||
},
|
||||
)) = error_predicate.kind().skip_binder()
|
||||
{
|
||||
let ty = trait_ref.self_ty();
|
||||
if let ty::Param(_) = ty.kind() {
|
||||
bounds.push((
|
||||
format!("{ty}"),
|
||||
trait_ref.print_only_trait_path().to_string(),
|
||||
Some(trait_ref.def_id),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
..
|
||||
})) = error_predicate.kind().skip_binder()
|
||||
{
|
||||
let ty = trait_ref.self_ty();
|
||||
if let ty::Param(_) = ty.kind() {
|
||||
bounds.push((
|
||||
format!("{ty}"),
|
||||
trait_ref.print_only_trait_path().to_string(),
|
||||
Some(trait_ref.def_id),
|
||||
));
|
||||
InfringingFieldsReason::Regions(region_errors) => {
|
||||
for error in region_errors {
|
||||
let ty = ty.to_string();
|
||||
match error {
|
||||
RegionResolutionError::ConcreteFailure(origin, a, b) => {
|
||||
let predicate = format!("{b}: {a}");
|
||||
errors
|
||||
.entry((ty.clone(), predicate.clone()))
|
||||
.or_default()
|
||||
.push(origin.span());
|
||||
if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
|
||||
bounds.push((b.to_string(), a.to_string(), None));
|
||||
}
|
||||
}
|
||||
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
|
||||
let predicate = format!("{a}: {b}");
|
||||
errors
|
||||
.entry((ty.clone(), predicate.clone()))
|
||||
.or_default()
|
||||
.push(origin.span());
|
||||
if let infer::region_constraints::GenericKind::Param(_) = a {
|
||||
bounds.push((a.to_string(), b.to_string(), None));
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -505,12 +524,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
|
|||
return err_info;
|
||||
} else if diff_fields.len() > 1 {
|
||||
let item = tcx.hir().expect_item(impl_did);
|
||||
let span =
|
||||
if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
|
||||
t.path.span
|
||||
} else {
|
||||
tcx.def_span(impl_did)
|
||||
};
|
||||
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
|
||||
t.path.span
|
||||
} else {
|
||||
tcx.def_span(impl_did)
|
||||
};
|
||||
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
}
|
||||
|
||||
let item = self.tcx.hir().item(id);
|
||||
let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, ref items, .. }) = item.kind else {
|
||||
let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, items, .. }) = item.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ fn do_orphan_check_impl<'tcx>(
|
|||
let trait_def_id = trait_ref.def_id;
|
||||
|
||||
let item = tcx.hir().expect_item(def_id);
|
||||
let hir::ItemKind::Impl(ref impl_) = item.kind else {
|
||||
let hir::ItemKind::Impl(impl_) = item.kind else {
|
||||
bug!("{:?} is not an impl: {:?}", def_id, item);
|
||||
};
|
||||
let sp = tcx.def_span(def_id);
|
||||
|
|
@ -416,13 +416,13 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
|
|||
if t != self.self_ty_root {
|
||||
for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
|
||||
match tcx.impl_polarity(impl_def_id) {
|
||||
ImplPolarity::Negative => return ControlFlow::BREAK,
|
||||
ImplPolarity::Negative => return ControlFlow::Break(()),
|
||||
ImplPolarity::Reservation => {}
|
||||
// FIXME(@lcnr): That's probably not good enough, idk
|
||||
//
|
||||
// We might just want to take the rustdoc code and somehow avoid
|
||||
// explicit impls for `Self`.
|
||||
ImplPolarity::Positive => return ControlFlow::CONTINUE,
|
||||
ImplPolarity::Positive => return ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -440,7 +440,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
|
|||
}
|
||||
}
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_span::def_id::LocalDefId;
|
|||
pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl));
|
||||
let item = tcx.hir().expect_item(def_id);
|
||||
let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
|
||||
let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
|
||||
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
|
||||
let trait_ref = trait_ref.subst_identity();
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
is_foreign_item,
|
||||
generator_kind,
|
||||
collect_mod_item_types,
|
||||
is_type_alias_impl_trait,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
|
@ -560,7 +561,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
debug!("convert: item {} with id {}", it.ident, it.hir_id());
|
||||
let def_id = item_id.owner_id.def_id;
|
||||
|
||||
match it.kind {
|
||||
match &it.kind {
|
||||
// These don't define types.
|
||||
hir::ItemKind::ExternCrate(_)
|
||||
| hir::ItemKind::Use(..)
|
||||
|
|
@ -568,7 +569,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
| hir::ItemKind::Mod(_)
|
||||
| hir::ItemKind::GlobalAsm(_) => {}
|
||||
hir::ItemKind::ForeignMod { items, .. } => {
|
||||
for item in items {
|
||||
for item in *items {
|
||||
let item = tcx.hir().foreign_item(item.id);
|
||||
tcx.ensure().generics_of(item.owner_id);
|
||||
tcx.ensure().type_of(item.owner_id);
|
||||
|
|
@ -618,7 +619,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
tcx.at(it.span).super_predicates_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
}
|
||||
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
|
||||
hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
|
|
@ -853,14 +854,14 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
|
|||
};
|
||||
|
||||
let repr = tcx.repr_options_of_def(def_id.to_def_id());
|
||||
let (kind, variants) = match item.kind {
|
||||
ItemKind::Enum(ref def, _) => {
|
||||
let (kind, variants) = match &item.kind {
|
||||
ItemKind::Enum(def, _) => {
|
||||
let mut distance_from_explicit = 0;
|
||||
let variants = def
|
||||
.variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let discr = if let Some(ref e) = v.disr_expr {
|
||||
let discr = if let Some(e) = &v.disr_expr {
|
||||
distance_from_explicit = 0;
|
||||
ty::VariantDiscr::Explicit(e.def_id.to_def_id())
|
||||
} else {
|
||||
|
|
@ -882,7 +883,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
|
|||
|
||||
(AdtKind::Enum, variants)
|
||||
}
|
||||
ItemKind::Struct(ref def, _) | ItemKind::Union(ref def, _) => {
|
||||
ItemKind::Struct(def, _) | ItemKind::Union(def, _) => {
|
||||
let adt_kind = match item.kind {
|
||||
ItemKind::Struct(..) => AdtKind::Struct,
|
||||
_ => AdtKind::Union,
|
||||
|
|
@ -1342,21 +1343,19 @@ fn suggest_impl_trait<'tcx>(
|
|||
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let item = tcx.hir().expect_item(def_id.expect_local());
|
||||
match item.kind {
|
||||
hir::ItemKind::Impl(ref impl_) => impl_
|
||||
.of_trait
|
||||
.as_ref()
|
||||
.map(|ast_trait_ref| {
|
||||
let selfty = tcx.type_of(def_id);
|
||||
icx.astconv().instantiate_mono_trait_ref(
|
||||
ast_trait_ref,
|
||||
selfty,
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||
)
|
||||
})
|
||||
.map(ty::EarlyBinder),
|
||||
_ => bug!(),
|
||||
}
|
||||
let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
|
||||
impl_
|
||||
.of_trait
|
||||
.as_ref()
|
||||
.map(|ast_trait_ref| {
|
||||
let selfty = tcx.type_of(def_id);
|
||||
icx.astconv().instantiate_mono_trait_ref(
|
||||
ast_trait_ref,
|
||||
selfty,
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||
)
|
||||
})
|
||||
.map(ty::EarlyBinder)
|
||||
}
|
||||
|
||||
fn check_impl_constness(
|
||||
|
|
@ -1511,7 +1510,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
|||
for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
|
||||
check(input, *ty)
|
||||
}
|
||||
if let hir::FnRetTy::Return(ref ty) = decl.output {
|
||||
if let hir::FnRetTy::Return(ty) = decl.output {
|
||||
check(ty, fty.output().skip_binder())
|
||||
}
|
||||
}
|
||||
|
|
@ -1537,3 +1536,13 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind>
|
|||
_ => bug!("generator_kind applied to non-local def-id {:?}", def_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||
match tcx.hir().get_if_local(def_id) {
|
||||
Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => {
|
||||
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
|
||||
}
|
||||
Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
|
||||
_ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,12 +110,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||
// expressions' count (i.e. `N` in `[x; N]`), and explicit
|
||||
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
|
||||
// as they shouldn't be able to cause query cycle errors.
|
||||
Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
|
||||
Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
|
||||
if constant.hir_id() == hir_id =>
|
||||
{
|
||||
Some(parent_def_id.to_def_id())
|
||||
}
|
||||
Node::Variant(Variant { disr_expr: Some(ref constant), .. })
|
||||
Node::Variant(Variant { disr_expr: Some(constant), .. })
|
||||
if constant.hir_id == hir_id =>
|
||||
{
|
||||
Some(parent_def_id.to_def_id())
|
||||
|
|
@ -259,7 +259,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||
|
||||
params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => None,
|
||||
GenericParamKind::Type { ref default, synthetic, .. } => {
|
||||
GenericParamKind::Type { default, synthetic, .. } => {
|
||||
if default.is_some() {
|
||||
match allow_defaults {
|
||||
Defaults::Allowed => {}
|
||||
|
|
@ -426,26 +426,22 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
}
|
||||
|
||||
match node {
|
||||
Node::TraitItem(item) => match item.kind {
|
||||
hir::TraitItemKind::Fn(ref sig, _) => {
|
||||
has_late_bound_regions(tcx, &item.generics, sig.decl)
|
||||
}
|
||||
Node::TraitItem(item) => match &item.kind {
|
||||
hir::TraitItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl),
|
||||
_ => None,
|
||||
},
|
||||
Node::ImplItem(item) => match item.kind {
|
||||
hir::ImplItemKind::Fn(ref sig, _) => {
|
||||
has_late_bound_regions(tcx, &item.generics, sig.decl)
|
||||
}
|
||||
Node::ImplItem(item) => match &item.kind {
|
||||
hir::ImplItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl),
|
||||
_ => None,
|
||||
},
|
||||
Node::ForeignItem(item) => match item.kind {
|
||||
hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
|
||||
hir::ForeignItemKind::Fn(fn_decl, _, generics) => {
|
||||
has_late_bound_regions(tcx, generics, fn_decl)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
|
||||
Node::Item(item) => match &item.kind {
|
||||
hir::ItemKind::Fn(sig, .., generics, _) => {
|
||||
has_late_bound_regions(tcx, generics, sig.decl)
|
||||
}
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -99,12 +99,16 @@ pub(super) fn explicit_item_bounds(
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
|
||||
tcx.mk_predicates(
|
||||
pub(super) fn item_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
|
||||
let bounds = tcx.mk_predicates(
|
||||
util::elaborate_predicates(
|
||||
tcx,
|
||||
tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
|
||||
)
|
||||
.map(|obligation| obligation.predicate),
|
||||
)
|
||||
);
|
||||
ty::EarlyBinder(bounds)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
match item.kind {
|
||||
hir::ItemKind::Fn(_, ref generics, _) => {
|
||||
hir::ItemKind::Fn(_, generics, _) => {
|
||||
self.visit_early_late(item.hir_id(), generics, |this| {
|
||||
intravisit::walk_item(this, item);
|
||||
});
|
||||
|
|
@ -508,13 +508,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
this.with(scope, |this| intravisit::walk_item(this, item))
|
||||
});
|
||||
}
|
||||
hir::ItemKind::TyAlias(_, ref generics)
|
||||
| hir::ItemKind::Enum(_, ref generics)
|
||||
| hir::ItemKind::Struct(_, ref generics)
|
||||
| hir::ItemKind::Union(_, ref generics)
|
||||
| hir::ItemKind::Trait(_, _, ref generics, ..)
|
||||
| hir::ItemKind::TraitAlias(ref generics, ..)
|
||||
| hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
|
||||
hir::ItemKind::TyAlias(_, generics)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Struct(_, generics)
|
||||
| hir::ItemKind::Union(_, generics)
|
||||
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||
| hir::ItemKind::TraitAlias(generics, ..)
|
||||
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
|
||||
// These kinds of items have only early-bound lifetime parameters.
|
||||
let lifetimes = generics
|
||||
.params
|
||||
|
|
@ -544,7 +544,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
|
||||
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(_, _, ref generics) => {
|
||||
hir::ForeignItemKind::Fn(_, _, generics) => {
|
||||
self.visit_early_late(item.hir_id(), generics, |this| {
|
||||
intravisit::walk_foreign_item(this, item);
|
||||
})
|
||||
|
|
@ -561,7 +561,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
match ty.kind {
|
||||
hir::TyKind::BareFn(ref c) => {
|
||||
hir::TyKind::BareFn(c) => {
|
||||
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
|
||||
.generic_params
|
||||
.iter()
|
||||
|
|
@ -587,7 +587,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
intravisit::walk_ty(this, ty);
|
||||
});
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
|
||||
hir::TyKind::TraitObject(bounds, lifetime, _) => {
|
||||
debug!(?bounds, ?lifetime, "TraitObject");
|
||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||
self.with(scope, |this| {
|
||||
|
|
@ -617,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
LifetimeName::Error => {}
|
||||
}
|
||||
}
|
||||
hir::TyKind::Ref(ref lifetime_ref, ref mt) => {
|
||||
hir::TyKind::Ref(lifetime_ref, ref mt) => {
|
||||
self.visit_lifetime(lifetime_ref);
|
||||
let scope = Scope::ObjectLifetimeDefault {
|
||||
lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
|
||||
|
|
@ -632,7 +632,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
// ^ ^ this gets resolved in the scope of
|
||||
// the opaque_ty generics
|
||||
let opaque_ty = self.tcx.hir().item(item_id);
|
||||
match opaque_ty.kind {
|
||||
match &opaque_ty.kind {
|
||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
||||
..
|
||||
|
|
@ -655,7 +655,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
|
||||
..
|
||||
}) => {}
|
||||
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
||||
i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
||||
};
|
||||
|
||||
// Resolve the lifetimes that are applied to the opaque type.
|
||||
|
|
@ -720,7 +720,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
intravisit::walk_trait_item(this, trait_item)
|
||||
});
|
||||
}
|
||||
Type(bounds, ref ty) => {
|
||||
Type(bounds, ty) => {
|
||||
let generics = &trait_item.generics;
|
||||
let lifetimes = generics
|
||||
.params
|
||||
|
|
@ -766,7 +766,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
|
||||
intravisit::walk_impl_item(this, impl_item)
|
||||
}),
|
||||
Type(ref ty) => {
|
||||
Type(ty) => {
|
||||
let generics = &impl_item.generics;
|
||||
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
|
||||
.params
|
||||
|
|
@ -817,7 +817,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
let depth = path.segments.len() - i - 1;
|
||||
if let Some(ref args) = segment.args {
|
||||
if let Some(args) = segment.args {
|
||||
self.visit_segment_args(path.res, depth, args);
|
||||
}
|
||||
}
|
||||
|
|
@ -833,7 +833,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
) {
|
||||
let output = match fd.output {
|
||||
hir::FnRetTy::DefaultReturn(_) => None,
|
||||
hir::FnRetTy::Return(ref ty) => Some(&**ty),
|
||||
hir::FnRetTy::Return(ty) => Some(ty),
|
||||
};
|
||||
self.visit_fn_like_elision(&fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
|
||||
intravisit::walk_fn_kind(self, fk);
|
||||
|
|
@ -846,13 +846,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
for param in generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { ref default, .. } => {
|
||||
if let Some(ref ty) = default {
|
||||
this.visit_ty(&ty);
|
||||
GenericParamKind::Type { default, .. } => {
|
||||
if let Some(ty) = default {
|
||||
this.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
GenericParamKind::Const { ref ty, default } => {
|
||||
this.visit_ty(&ty);
|
||||
GenericParamKind::Const { ty, default } => {
|
||||
this.visit_ty(ty);
|
||||
if let Some(default) = default {
|
||||
this.visit_body(this.tcx.hir().body(default.body));
|
||||
}
|
||||
|
|
@ -863,9 +863,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
match predicate {
|
||||
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
hir_id,
|
||||
ref bounded_ty,
|
||||
bounded_ty,
|
||||
bounds,
|
||||
ref bound_generic_params,
|
||||
bound_generic_params,
|
||||
origin,
|
||||
..
|
||||
}) => {
|
||||
|
|
@ -905,7 +905,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
||||
ref lifetime,
|
||||
lifetime,
|
||||
bounds,
|
||||
..
|
||||
}) => {
|
||||
|
|
@ -914,7 +914,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
|
||||
if lifetime.res != hir::LifetimeName::Static {
|
||||
for bound in bounds {
|
||||
let hir::GenericBound::Outlives(ref lt) = bound else {
|
||||
let hir::GenericBound::Outlives(lt) = bound else {
|
||||
continue;
|
||||
};
|
||||
if lt.res != hir::LifetimeName::Static {
|
||||
|
|
@ -939,8 +939,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
ref lhs_ty,
|
||||
ref rhs_ty,
|
||||
lhs_ty,
|
||||
rhs_ty,
|
||||
..
|
||||
}) => {
|
||||
this.visit_ty(lhs_ty);
|
||||
|
|
@ -1042,7 +1042,7 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifeti
|
|||
}
|
||||
|
||||
for bound in bound.bounds {
|
||||
if let hir::GenericBound::Outlives(ref lifetime) = *bound {
|
||||
if let hir::GenericBound::Outlives(lifetime) = bound {
|
||||
set.insert(lifetime.res);
|
||||
}
|
||||
}
|
||||
|
|
@ -1828,7 +1828,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
|
|||
}
|
||||
}
|
||||
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
|
||||
// consider only the lifetimes on the final
|
||||
// segment; I am not sure it's even currently
|
||||
// valid to have them elsewhere, but even if it
|
||||
|
|
|
|||
|
|
@ -85,30 +85,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
Node::ImplItem(item) => item.generics,
|
||||
|
||||
Node::Item(item) => match item.kind {
|
||||
ItemKind::Impl(ref impl_) => {
|
||||
ItemKind::Impl(impl_) => {
|
||||
if impl_.defaultness.is_default() {
|
||||
is_default_impl_trait =
|
||||
tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity()));
|
||||
}
|
||||
&impl_.generics
|
||||
impl_.generics
|
||||
}
|
||||
ItemKind::Fn(.., ref generics, _)
|
||||
| ItemKind::TyAlias(_, ref generics)
|
||||
| ItemKind::Enum(_, ref generics)
|
||||
| ItemKind::Struct(_, ref generics)
|
||||
| ItemKind::Union(_, ref generics) => *generics,
|
||||
ItemKind::Fn(.., generics, _)
|
||||
| ItemKind::TyAlias(_, generics)
|
||||
| ItemKind::Enum(_, generics)
|
||||
| ItemKind::Struct(_, generics)
|
||||
| ItemKind::Union(_, generics) => generics,
|
||||
|
||||
ItemKind::Trait(_, _, ref generics, ..) | ItemKind::TraitAlias(ref generics, _) => {
|
||||
ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => {
|
||||
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
|
||||
*generics
|
||||
generics
|
||||
}
|
||||
ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
|
||||
ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics,
|
||||
_ => NO_GENERICS,
|
||||
},
|
||||
|
||||
Node::ForeignItem(item) => match item.kind {
|
||||
ForeignItemKind::Static(..) => NO_GENERICS,
|
||||
ForeignItemKind::Fn(_, _, ref generics) => *generics,
|
||||
ForeignItemKind::Fn(_, _, generics) => generics,
|
||||
ForeignItemKind::Type => NO_GENERICS,
|
||||
},
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ fn const_evaluatable_predicates_of(
|
|||
let node = tcx.hir().get(hir_id);
|
||||
|
||||
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
|
||||
if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
|
||||
if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind {
|
||||
if let Some(of_trait) = &impl_.of_trait {
|
||||
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
|
||||
collector.visit_trait_ref(of_trait);
|
||||
|
|
@ -511,8 +511,8 @@ pub(super) fn super_predicates_that_define_assoc_type(
|
|||
};
|
||||
|
||||
let (generics, bounds) = match item.kind {
|
||||
hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
|
||||
hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
|
||||
_ => span_bug!(item.span, "super_predicates invoked on non-trait"),
|
||||
};
|
||||
|
||||
|
|
@ -612,18 +612,18 @@ pub(super) fn type_param_predicates(
|
|||
|
||||
Node::Item(item) => {
|
||||
match item.kind {
|
||||
ItemKind::Fn(.., ref generics, _)
|
||||
| ItemKind::Impl(hir::Impl { ref generics, .. })
|
||||
| ItemKind::TyAlias(_, ref generics)
|
||||
ItemKind::Fn(.., generics, _)
|
||||
| ItemKind::Impl(&hir::Impl { generics, .. })
|
||||
| ItemKind::TyAlias(_, generics)
|
||||
| ItemKind::OpaqueTy(OpaqueTy {
|
||||
ref generics,
|
||||
generics,
|
||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
||||
..
|
||||
})
|
||||
| ItemKind::Enum(_, ref generics)
|
||||
| ItemKind::Struct(_, ref generics)
|
||||
| ItemKind::Union(_, ref generics) => generics,
|
||||
ItemKind::Trait(_, _, ref generics, ..) => {
|
||||
| ItemKind::Enum(_, generics)
|
||||
| ItemKind::Struct(_, generics)
|
||||
| ItemKind::Union(_, generics) => generics,
|
||||
ItemKind::Trait(_, _, generics, ..) => {
|
||||
// Implied `Self: Trait` and supertrait bounds.
|
||||
if param_id == item_hir_id {
|
||||
let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
|
||||
|
|
@ -637,7 +637,7 @@ pub(super) fn type_param_predicates(
|
|||
}
|
||||
|
||||
Node::ForeignItem(item) => match item.kind {
|
||||
ForeignItemKind::Fn(_, _, ref generics) => generics,
|
||||
ForeignItemKind::Fn(_, _, generics) => generics,
|
||||
_ => return result,
|
||||
},
|
||||
|
||||
|
|
@ -681,8 +681,8 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
ast_generics
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|wp| match *wp {
|
||||
hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
|
||||
.filter_map(|wp| match wp {
|
||||
hir::WherePredicate::BoundPredicate(bp) => Some(bp),
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|bp| {
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
|
||||
},
|
||||
|
||||
Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
|
||||
Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def {
|
||||
VariantData::Unit(..) | VariantData::Struct(..) => {
|
||||
tcx.type_of(tcx.hir().get_parent_item(hir_id))
|
||||
}
|
||||
|
|
@ -404,17 +404,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
Node::AnonConst(_) => {
|
||||
let parent_node = tcx.hir().get_parent(hir_id);
|
||||
match parent_node {
|
||||
Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
|
||||
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
|
||||
Node::Ty(Ty { kind: TyKind::Array(_, constant), .. })
|
||||
| Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
|
||||
if constant.hir_id() == hir_id =>
|
||||
{
|
||||
tcx.types.usize
|
||||
}
|
||||
Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
|
||||
Node::Ty(Ty { kind: TyKind::Typeof(e), .. }) if e.hir_id == hir_id => {
|
||||
tcx.typeck(def_id).node_type(e.hir_id)
|
||||
}
|
||||
|
||||
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
|
||||
Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. })
|
||||
if anon_const.hir_id == hir_id =>
|
||||
{
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||
|
|
@ -434,18 +434,19 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
tcx.typeck(def_id).node_type(hir_id)
|
||||
}
|
||||
|
||||
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
|
||||
Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
|
||||
tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
|
||||
}
|
||||
|
||||
Node::TypeBinding(
|
||||
binding @ &TypeBinding {
|
||||
TypeBinding {
|
||||
hir_id: binding_id,
|
||||
kind: TypeBindingKind::Equality { term: Term::Const(ref e) },
|
||||
kind: TypeBindingKind::Equality { term: Term::Const(e) },
|
||||
ident,
|
||||
..
|
||||
},
|
||||
) if let Node::TraitRef(trait_ref) =
|
||||
tcx.hir().get_parent(binding_id)
|
||||
tcx.hir().get_parent(*binding_id)
|
||||
&& e.hir_id == hir_id =>
|
||||
{
|
||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||
|
|
@ -454,7 +455,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
let assoc_items = tcx.associated_items(trait_def_id);
|
||||
let assoc_item = assoc_items.find_by_name_and_kind(
|
||||
tcx,
|
||||
binding.ident,
|
||||
*ident,
|
||||
ty::AssocKind::Const,
|
||||
def_id.to_def_id(),
|
||||
);
|
||||
|
|
@ -470,9 +471,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
}
|
||||
|
||||
Node::TypeBinding(
|
||||
binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. },
|
||||
TypeBinding { hir_id: binding_id, gen_args, kind, ident, .. },
|
||||
) if let Node::TraitRef(trait_ref) =
|
||||
tcx.hir().get_parent(binding_id)
|
||||
tcx.hir().get_parent(*binding_id)
|
||||
&& let Some((idx, _)) =
|
||||
gen_args.args.iter().enumerate().find(|(_, arg)| {
|
||||
if let GenericArg::Const(ct) = arg {
|
||||
|
|
@ -488,7 +489,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
let assoc_items = tcx.associated_items(trait_def_id);
|
||||
let assoc_item = assoc_items.find_by_name_and_kind(
|
||||
tcx,
|
||||
binding.ident,
|
||||
*ident,
|
||||
match kind {
|
||||
// I think `<A: T>` type bindings requires that `A` is a type
|
||||
TypeBindingKind::Constraint { .. }
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
|
|||
match *t.kind() {
|
||||
ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
|
||||
// projections are not injective
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
ty::Param(data) => {
|
||||
self.parameters.push(Parameter::from(data));
|
||||
|
|
@ -76,7 +76,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
|
|||
if let ty::ReEarlyBound(data) = *r {
|
||||
self.parameters.push(Parameter::from(data));
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
},
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
|
||||
hir::ItemKind::Impl(ref impl_) => match &impl_.of_trait {
|
||||
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
|
||||
Some(t) => t
|
||||
.path
|
||||
.segments
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
|||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
|
||||
use std::iter;
|
||||
use std::ops::Not;
|
||||
|
||||
use astconv::AstConv;
|
||||
use bounds::Bounds;
|
||||
|
|
@ -203,12 +204,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
|||
}
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir().find(hir_id) {
|
||||
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
|
||||
if !generics.params.is_empty() {
|
||||
Some(generics.span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
|
||||
generics.params.is_empty().not().then(|| generics.span)
|
||||
}
|
||||
_ => {
|
||||
span_bug!(tcx.def_span(def_id), "main has a non-function type");
|
||||
|
|
@ -222,7 +219,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
|||
}
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir().find(hir_id) {
|
||||
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
|
||||
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
|
||||
Some(generics.where_clause_span)
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -244,7 +241,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
|||
}
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir().find(hir_id) {
|
||||
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => {
|
||||
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => {
|
||||
Some(fn_sig.decl.output.span())
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -374,7 +371,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
|
|||
match start_t.kind() {
|
||||
ty::FnDef(..) => {
|
||||
if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
|
||||
if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
|
||||
if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
|
||||
let mut error = false;
|
||||
if !generics.params.is_empty() {
|
||||
struct_span_err!(
|
||||
|
|
|
|||
|
|
@ -80,8 +80,8 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
|
|||
.or_insert(span);
|
||||
}
|
||||
|
||||
Component::Projection(proj_ty) => {
|
||||
// This would arise from something like:
|
||||
Component::Alias(alias_ty) => {
|
||||
// This would either arise from something like:
|
||||
//
|
||||
// ```
|
||||
// struct Foo<'a, T: Iterator> {
|
||||
|
|
@ -89,15 +89,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
|
|||
// }
|
||||
// ```
|
||||
//
|
||||
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
|
||||
let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.def_id, proj_ty.substs);
|
||||
required_predicates
|
||||
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
|
||||
.or_insert(span);
|
||||
}
|
||||
|
||||
Component::Opaque(def_id, substs) => {
|
||||
// This would arise from something like:
|
||||
// or:
|
||||
//
|
||||
// ```rust
|
||||
// type Opaque<T> = impl Sized;
|
||||
|
|
@ -105,15 +97,15 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
|
|||
// struct Ss<'a, T>(&'a Opaque<T>);
|
||||
// ```
|
||||
//
|
||||
// Here we want to have an implied bound `Opaque<T>: 'a`
|
||||
|
||||
let ty = tcx.mk_opaque(def_id, substs);
|
||||
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`
|
||||
// or `Opaque<T>: 'a` depending on the alias kind.
|
||||
let ty = alias_ty.to_ty(tcx);
|
||||
required_predicates
|
||||
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
|
||||
.or_insert(span);
|
||||
}
|
||||
|
||||
Component::EscapingProjection(_) => {
|
||||
Component::EscapingAlias(_) => {
|
||||
// As above, but the projection involves
|
||||
// late-bound regions. Therefore, the WF
|
||||
// requirement is not checked in type definition
|
||||
|
|
|
|||
|
|
@ -727,8 +727,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
|
||||
&& let Some(parent_node) = self.tcx.hir().find(parent_node)
|
||||
&& let hir::Node::Expr(expr) = parent_node {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Path(ref qpath) => {
|
||||
match &expr.kind {
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
|
||||
err,
|
||||
qpath,
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
|||
a.visit_with(self)?;
|
||||
}
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
substs.visit_with(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
//! optimal solution to the constraints. The final variance for each
|
||||
//! inferred is then written into the `variance_map` in the tcx.
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_middle::ty;
|
||||
|
||||
use super::constraints::*;
|
||||
|
|
@ -28,8 +27,8 @@ pub fn solve_constraints<'tcx>(
|
|||
let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
|
||||
|
||||
let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
|
||||
for &(id, ref variances) in &terms_cx.lang_items {
|
||||
let InferredIndex(start) = terms_cx.inferred_starts[&id];
|
||||
for (id, variances) in &terms_cx.lang_items {
|
||||
let InferredIndex(start) = terms_cx.inferred_starts[id];
|
||||
for (i, &variance) in variances.iter().enumerate() {
|
||||
solutions[start + i] = variance;
|
||||
}
|
||||
|
|
@ -89,14 +88,12 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_map(&self) -> FxHashMap<DefId, &'tcx [ty::Variance]> {
|
||||
fn create_map(&self) -> DefIdMap<&'tcx [ty::Variance]> {
|
||||
let tcx = self.terms_cx.tcx;
|
||||
|
||||
let solutions = &self.solutions;
|
||||
self.terms_cx
|
||||
.inferred_starts
|
||||
.iter()
|
||||
.map(|(&def_id, &InferredIndex(start))| {
|
||||
DefIdMap::from(self.terms_cx.inferred_starts.items().map(
|
||||
|(&def_id, &InferredIndex(start))| {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let count = generics.count();
|
||||
|
||||
|
|
@ -115,8 +112,8 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
(def_id.to_def_id(), &*variances)
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use rustc_errors::struct_span_err;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
|
|
@ -8,8 +7,8 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
|
|||
for id in tcx.hir().items() {
|
||||
if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
|
||||
let variances_of = tcx.variances_of(id.owner_id);
|
||||
struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
|
||||
.emit();
|
||||
|
||||
tcx.sess.struct_span_err(tcx.def_span(id.owner_id), format!("{variances_of:?}")).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue