Auto merge of #2762 - RalfJung:rustup, r=RalfJung

Rustup
This commit is contained in:
bors 2023-01-23 01:41:56 +00:00
commit 20180540e6
703 changed files with 10302 additions and 5405 deletions

View file

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

View file

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

@ -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 youd like to build the documentation, its 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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()
}
```

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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