Auto merge of #3267 - rust-lang:rustup-2024-01-14, r=saethlin

Automatic Rustup
This commit is contained in:
bors 2024-01-14 05:53:49 +00:00
commit 0c8e1e6f44
837 changed files with 4241 additions and 1345 deletions

View file

@ -18,6 +18,7 @@ Files: compiler/*
configure
CONTRIBUTING.md
COPYRIGHT
INSTALL.md
LICENSE-APACHE
LICENSE-MIT
README.md
@ -51,7 +52,7 @@ Copyright: 2019 The Crossbeam Project Developers
The Rust Project Developers (see https://thanks.rust-lang.org)
License: MIT OR Apache-2.0
Files: library/std/src/sys/unix/locks/fuchsia_mutex.rs
Files: library/std/src/sys/pal/unix/locks/fuchsia_mutex.rs
Copyright: 2016 The Fuchsia Authors
The Rust Project Developers (see https://thanks.rust-lang.org)
License: BSD-2-Clause AND (MIT OR Apache-2.0)

253
INSTALL.md Normal file
View file

@ -0,0 +1,253 @@
# Installing from Source
**Note: This document describes _building_ Rust _from source_.
This is _not recommended_ if you don't know what you're doing.
If you just want to install Rust, check out the [README.md](README.md) instead.**
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.
It also uses a file named `config.toml` to determine various configuration
settings for the build. You can see a full list of options in
`config.example.toml`.
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`.
See the [rustc dev guide][rustcguidebuild] if this does not work on your
platform.
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#what-is-xpy
## Dependencies
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)
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)
* `cmake` 3.13.4 or later
* `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`.
Otherwise, you'll need LLVM installed and `llvm-config` in your path.
See [the rustc-dev-guide for more info][sysllvm].
[sysllvm]: https://rustc-dev-guide.rust-lang.org/building/new-target.html#using-pre-built-llvm
## Building on a Unix-like system
### Build steps
1. Clone the [source] with `git`:
```sh
git clone https://github.com/rust-lang/rust.git
cd rust
```
[source]: https://github.com/rust-lang/rust
2. Configure the build settings:
```sh
./configure
```
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: `./configure --set install.prefix=<path>`
3. Build and 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. By default, it will also include [Cargo], Rust's
package manager. You can disable this behavior by passing
`--set build.extended=false` to `./configure`.
[Cargo]: https://github.com/rust-lang/cargo
### Configure and Make
This project provides a configure script and makefile (the latter of which just
invokes `x.py`). `./configure` is the recommended way to programmatically
generate a `config.toml`. `make` is not recommended (we suggest using `x.py`
directly), but it is supported and we try not to break it unnecessarily.
```sh
./configure
make && sudo make install
```
`configure` generates a `config.toml` which can also be used with normal `x.py`
invocations.
## Building on Windows
On Windows, we suggest using [winget] to install dependencies by running the
following in a terminal:
```powershell
winget install -e Python.Python.3
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.
[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.
### MinGW
[MSYS2][msys2] can be used to easily build Rust on Windows:
[msys2]: https://www.msys2.org/
1. Download the latest [MSYS2 installer][msys2] and go through the installer.
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.)
3. From this terminal, install the required tools:
```sh
# Update package mirrors (may be needed if you have a fresh install of MSYS2)
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.
pacman -S git \
make \
diffutils \
tar \
mingw-w64-x86_64-python \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-gcc \
mingw-w64-x86_64-ninja
```
4. Navigate to Rust's source code (or clone it), then build it:
```sh
python x.py setup user && python x.py build && python x.py install
```
### MSVC
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]: 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".)
With these dependencies installed, you can build the compiler in a `cmd.exe`
shell with:
```sh
python x.py setup user
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.
```batch
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
python x.py build
```
### Specifying an ABI
Each specific ABI can also be used from either environment (for example, using
the GNU ABI in PowerShell) by using an explicit build triple. The available
Windows build triples are:
- GNU ABI (using GCC)
- `i686-pc-windows-gnu`
- `x86_64-pc-windows-gnu`
- The MSVC ABI
- `i686-pc-windows-msvc`
- `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
[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing
`--set build.build=<triple>` to `./configure`.
## Building Documentation
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. 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.
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.

253
README.md
View file

@ -15,9 +15,6 @@ If you wish to _contribute_ to the compiler, you should read
<summary>Table of Contents</summary>
- [Quick Start](#quick-start)
- [Installing from Source](#installing-from-source)
- [Building Documentation](#building-documentation)
- [Notes](#notes)
- [Getting Help](#getting-help)
- [Contributing](#contributing)
- [License](#license)
@ -32,255 +29,9 @@ Read ["Installation"] from [The Book].
["Installation"]: https://doc.rust-lang.org/book/ch01-01-installation.html
[The Book]: https://doc.rust-lang.org/book/index.html
## Installing from Source
## Installing from source
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.
It also uses a file named `config.toml` to determine various configuration
settings for the build. You can see a full list of options in
`config.example.toml`.
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`.
See the [rustc dev guide][rustcguidebuild] if this does not work on your
platform.
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#what-is-xpy
### Dependencies
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)
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)
* `cmake` 3.13.4 or later
* `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`.
Otherwise, you'll need LLVM installed and `llvm-config` in your path.
See [the rustc-dev-guide for more info][sysllvm].
[sysllvm]: https://rustc-dev-guide.rust-lang.org/building/new-target.html#using-pre-built-llvm
### Building on a Unix-like system
#### Build steps
1. Clone the [source] with `git`:
```sh
git clone https://github.com/rust-lang/rust.git
cd rust
```
[source]: https://github.com/rust-lang/rust
2. Configure the build settings:
```sh
./configure
```
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: `./configure --set install.prefix=<path>`
3. Build and 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. By default, it will also include [Cargo], Rust's
package manager. You can disable this behavior by passing
`--set build.extended=false` to `./configure`.
[Cargo]: https://github.com/rust-lang/cargo
#### Configure and Make
This project provides a configure script and makefile (the latter of which just
invokes `x.py`). `./configure` is the recommended way to programmatically
generate a `config.toml`. `make` is not recommended (we suggest using `x.py`
directly), but it is supported and we try not to break it unnecessarily.
```sh
./configure
make && sudo make install
```
`configure` generates a `config.toml` which can also be used with normal `x.py`
invocations.
### Building on Windows
On Windows, we suggest using [winget] to install dependencies by running the
following in a terminal:
```powershell
winget install -e Python.Python.3
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.
[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.
#### MinGW
[MSYS2][msys2] can be used to easily build Rust on Windows:
[msys2]: https://www.msys2.org/
1. Download the latest [MSYS2 installer][msys2] and go through the installer.
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.)
3. From this terminal, install the required tools:
```sh
# Update package mirrors (may be needed if you have a fresh install of MSYS2)
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.
pacman -S git \
make \
diffutils \
tar \
mingw-w64-x86_64-python \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-gcc \
mingw-w64-x86_64-ninja
```
4. Navigate to Rust's source code (or clone it), then build it:
```sh
python x.py setup user && python x.py build && python x.py install
```
#### MSVC
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]: 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".)
With these dependencies installed, you can build the compiler in a `cmd.exe`
shell with:
```sh
python x.py setup user
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.
```batch
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
python x.py build
```
#### Specifying an ABI
Each specific ABI can also be used from either environment (for example, using
the GNU ABI in PowerShell) by using an explicit build triple. The available
Windows build triples are:
- GNU ABI (using GCC)
- `i686-pc-windows-gnu`
- `x86_64-pc-windows-gnu`
- The MSVC ABI
- `i686-pc-windows-msvc`
- `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
[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing
`--set build.build=<triple>` to `./configure`.
## Building Documentation
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. 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.
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.
If you really want to install from source (though this is not recommended), see [INSTALL.md](INSTALL.md).
## Getting Help

View file

@ -2873,6 +2873,7 @@ impl Item {
| ItemKind::ForeignMod(_)
| ItemKind::GlobalAsm(_)
| ItemKind::MacCall(_)
| ItemKind::Delegation(_)
| ItemKind::MacroDef(_) => None,
ItemKind::Static(_) => None,
ItemKind::Const(i) => Some(&i.generics),
@ -3019,6 +3020,15 @@ pub struct Fn {
pub body: Option<P<Block>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct Delegation {
/// Path resolution id.
pub id: NodeId,
pub qself: Option<P<QSelf>>,
pub path: Path,
pub body: Option<P<Block>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem {
pub ty: P<Ty>,
@ -3104,6 +3114,11 @@ pub enum ItemKind {
/// A macro definition.
MacroDef(MacroDef),
/// A delegation item (`reuse`).
///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>),
}
impl ItemKind {
@ -3111,7 +3126,8 @@ impl ItemKind {
use ItemKind::*;
match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) => "a",
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
| Delegation(..) => "a",
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
}
}
@ -3135,6 +3151,7 @@ impl ItemKind {
ItemKind::MacCall(..) => "item macro invocation",
ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation",
ItemKind::Delegation(..) => "delegated function",
}
}
@ -3176,6 +3193,8 @@ pub enum AssocItemKind {
Type(Box<TyAlias>),
/// A macro expanding to associated items.
MacCall(P<MacCall>),
/// An associated delegation item.
Delegation(Box<Delegation>),
}
impl AssocItemKind {
@ -3184,7 +3203,7 @@ impl AssocItemKind {
Self::Const(box ConstItem { defaultness, .. })
| Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) => Defaultness::Final,
Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
}
}
}
@ -3196,6 +3215,7 @@ impl From<AssocItemKind> for ItemKind {
AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
}
}
}
@ -3209,6 +3229,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
_ => return Err(item_kind),
})
}

View file

@ -1117,6 +1117,14 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
}
ItemKind::MacCall(m) => vis.visit_mac_call(m),
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
vis.visit_id(id);
vis.visit_qself(qself);
vis.visit_path(path);
if let Some(body) = body {
vis.visit_block(body);
}
}
}
}
@ -1155,6 +1163,14 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
visitor.visit_id(id);
visitor.visit_qself(qself);
visitor.visit_path(path);
if let Some(body) = body {
visitor.visit_block(body);
}
}
}
visitor.visit_span(span);
visit_lazy_tts(tokens, visitor);

View file

@ -375,6 +375,15 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
}
ItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id),
ItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
if let Some(qself) = qself {
visitor.visit_ty(&qself.ty);
}
walk_path(visitor, path);
if let Some(body) = body {
visitor.visit_block(body);
}
}
}
walk_list!(visitor, visit_attribute, &item.attrs);
}
@ -704,6 +713,15 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
AssocItemKind::MacCall(mac) => {
visitor.visit_mac_call(mac);
}
AssocItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
if let Some(qself) = qself {
visitor.visit_ty(&qself.ty);
}
walk_path(visitor, path);
if let Some(body) = body {
visitor.visit_block(body);
}
}
}
}

View file

@ -48,7 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
if !is_stable && !self.tcx.features().asm_experimental_arch {
feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::asm_experimental_arch,
sp,
"inline assembly is not stable yet on this architecture",
@ -63,13 +63,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
}
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
feature_err(
&self.tcx.sess.parse_sess,
sym::asm_unwind,
sp,
"the `may_unwind` option is unstable",
)
.emit();
feature_err(&self.tcx.sess, sym::asm_unwind, sp, "the `may_unwind` option is unstable")
.emit();
}
let mut clobber_abis = FxIndexMap::default();
@ -183,7 +178,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
InlineAsmOperand::Const { anon_const } => {
if !self.tcx.features().asm_const {
feature_err(
&sess.parse_sess,
sess,
sym::asm_const,
*op_sp,
"const operands for inline assembly are unstable",

View file

@ -0,0 +1,348 @@
//! This module implements expansion of delegation items with early resolved paths.
//! It includes a delegation to a free functions:
//!
//! ```ignore (illustrative)
//! reuse module::name { target_expr_template }
//! ```
//!
//! And delegation to a trait methods:
//!
//! ```ignore (illustrative)
//! reuse <Type as Trait>::name { target_expr_template }
//! ```
//!
//! After expansion for both cases we get:
//!
//! ```ignore (illustrative)
//! fn name(
//! arg0: InferDelegation(sig_id, Input(0)),
//! arg1: InferDelegation(sig_id, Input(1)),
//! ...,
//! argN: InferDelegation(sig_id, Input(N)),
//! ) -> InferDelegation(sig_id, Output) {
//! callee_path(target_expr_template(arg0), arg1, ..., argN)
//! }
//! ```
//!
//! Where `callee_path` is a path in delegation item e.g. `<Type as Trait>::name`.
//! `sig_id` is a id of item from which the signature is inherited. It may be a delegation
//! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise.
//!
//! Since we do not have a proper way to obtain function type information by path resolution
//! in AST, we mark each function parameter type as `InferDelegation` and inherit it in `AstConv`.
//!
//! Similarly generics, predicates and header are set to the "default" values.
//! In case of discrepancy with callee function the `NotSupportedDelegation` error will
//! also be emitted in `AstConv`.
use crate::{ImplTraitPosition, ResolverAstLoweringExt};
use super::{ImplTraitContext, LoweringContext, ParamMode};
use ast::visit::Visitor;
use hir::def::{DefKind, PartialRes, Res};
use hir::{BodyId, HirId};
use rustc_ast as ast;
use rustc_ast::*;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::ty::ResolverAstLowering;
use rustc_span::{symbol::Ident, Span};
use rustc_target::spec::abi;
use std::iter;
pub(crate) struct DelegationResults<'hir> {
pub body_id: hir::BodyId,
pub sig: hir::FnSig<'hir>,
pub generics: &'hir hir::Generics<'hir>,
}
impl<'hir> LoweringContext<'_, 'hir> {
pub(crate) fn delegation_has_self(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool {
let sig_id = self.get_delegation_sig_id(item_id, path_id, span);
let Ok(sig_id) = sig_id else {
return false;
};
if let Some(local_sig_id) = sig_id.as_local() {
self.resolver.has_self.contains(&local_sig_id)
} else {
match self.tcx.def_kind(sig_id) {
DefKind::Fn => false,
DefKind::AssocFn => self.tcx.associated_item(sig_id).fn_has_self_parameter,
_ => span_bug!(span, "unexpected DefKind for delegation item"),
}
}
}
pub(crate) fn lower_delegation(
&mut self,
delegation: &Delegation,
item_id: NodeId,
) -> DelegationResults<'hir> {
let span = delegation.path.segments.last().unwrap().ident.span;
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span);
match sig_id {
Ok(sig_id) => {
let decl = self.lower_delegation_decl(sig_id, span);
let sig = self.lower_delegation_sig(span, decl);
let body_id = self.lower_delegation_body(sig.decl, delegation);
let generics = self.lower_delegation_generics(span);
DelegationResults { body_id, sig, generics }
}
Err(err) => self.generate_delegation_error(err, span),
}
}
fn get_delegation_sig_id(
&self,
item_id: NodeId,
path_id: NodeId,
span: Span,
) -> Result<DefId, ErrorGuaranteed> {
let sig_id = if self.is_in_trait_impl { item_id } else { path_id };
let sig_id = self
.resolver
.get_partial_res(sig_id)
.map(|r| r.expect_full_res().opt_def_id())
.unwrap_or(None);
sig_id.ok_or_else(|| {
self.tcx
.dcx()
.span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item")
})
}
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
self.arena.alloc(hir::Generics {
params: &[],
predicates: &[],
has_where_clause_predicates: false,
where_clause_span: span,
span: span,
})
}
fn lower_delegation_decl(
&mut self,
sig_id: DefId,
param_span: Span,
) -> &'hir hir::FnDecl<'hir> {
let args_count = if let Some(local_sig_id) = sig_id.as_local() {
// Map may be filled incorrectly due to recursive delegation.
// Error will be emmited later in astconv.
self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default()
} else {
self.tcx.fn_arg_names(sig_id).len()
};
let inputs = self.arena.alloc_from_iter((0..args_count).into_iter().map(|arg| hir::Ty {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
span: self.lower_span(param_span),
}));
let output = self.arena.alloc(hir::Ty {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
span: self.lower_span(param_span),
});
self.arena.alloc(hir::FnDecl {
inputs,
output: hir::FnRetTy::Return(output),
c_variadic: false,
lifetime_elision_allowed: true,
implicit_self: hir::ImplicitSelfKind::None,
})
}
fn lower_delegation_sig(
&mut self,
span: Span,
decl: &'hir hir::FnDecl<'hir>,
) -> hir::FnSig<'hir> {
hir::FnSig {
decl,
header: hir::FnHeader {
unsafety: hir::Unsafety::Normal,
constness: hir::Constness::NotConst,
asyncness: hir::IsAsync::NotAsync,
abi: abi::Abi::Rust,
},
span: self.lower_span(span),
}
}
fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) {
let pat_node_id = self.next_node_id();
let pat_id = self.lower_node_id(pat_node_id);
let pat = self.arena.alloc(hir::Pat {
hir_id: pat_id,
kind: hir::PatKind::Binding(hir::BindingAnnotation::NONE, pat_id, Ident::empty(), None),
span: ty.span,
default_binding_modes: false,
});
(hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id)
}
fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> {
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
ident: Ident::empty(),
hir_id: self.next_id(),
res: Res::Local(param_id),
args: None,
infer_args: false,
}));
let path =
self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments });
hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
span: ty.span,
}
}
fn lower_delegation_body(
&mut self,
decl: &'hir hir::FnDecl<'hir>,
delegation: &Delegation,
) -> BodyId {
let path = self.lower_qpath(
delegation.id,
&delegation.qself,
&delegation.path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
let block = delegation.body.as_deref();
self.lower_body(|this| {
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
let mut args: Vec<hir::Expr<'hir>> = Vec::new();
for (idx, param_ty) in decl.inputs.iter().enumerate() {
let (param, pat_node_id) = this.generate_param(param_ty);
parameters.push(param);
let arg = if let Some(block) = block
&& idx == 0
{
let mut self_resolver = SelfResolver {
resolver: this.resolver,
path_id: delegation.id,
self_param_id: pat_node_id,
};
self_resolver.visit_block(block);
let block = this.lower_block(block, false);
hir::Expr {
hir_id: this.next_id(),
kind: hir::ExprKind::Block(block, None),
span: block.span,
}
} else {
let pat_hir_id = this.lower_node_id(pat_node_id);
this.generate_arg(param_ty, pat_hir_id)
};
args.push(arg);
}
let args = self.arena.alloc_from_iter(args);
let final_expr = this.generate_call(path, args);
(this.arena.alloc_from_iter(parameters), final_expr)
})
}
fn generate_call(
&mut self,
path: hir::QPath<'hir>,
args: &'hir [hir::Expr<'hir>],
) -> hir::Expr<'hir> {
let callee = self.arena.alloc(hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::Path(path),
span: path.span(),
});
let expr = self.arena.alloc(hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::Call(callee, args),
span: path.span(),
});
let block = self.arena.alloc(hir::Block {
stmts: &[],
expr: Some(expr),
hir_id: self.next_id(),
rules: hir::BlockCheckMode::DefaultBlock,
span: path.span(),
targeted_by_break: false,
});
hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::Block(block, None),
span: path.span(),
}
}
fn generate_delegation_error(
&mut self,
err: ErrorGuaranteed,
span: Span,
) -> DelegationResults<'hir> {
let generics = self.lower_delegation_generics(span);
let decl = self.arena.alloc(hir::FnDecl {
inputs: &[],
output: hir::FnRetTy::DefaultReturn(span),
c_variadic: false,
lifetime_elision_allowed: true,
implicit_self: hir::ImplicitSelfKind::None,
});
let sig = self.lower_delegation_sig(span, decl);
let body_id = self.lower_body(|this| {
let expr =
hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span };
(&[], expr)
});
DelegationResults { generics, body_id, sig }
}
}
struct SelfResolver<'a> {
resolver: &'a mut ResolverAstLowering,
path_id: NodeId,
self_param_id: NodeId,
}
impl<'a> SelfResolver<'a> {
fn try_replace_id(&mut self, id: NodeId) {
if let Some(res) = self.resolver.partial_res_map.get(&id)
&& let Some(Res::Local(sig_id)) = res.full_res()
&& sig_id == self.path_id
{
let new_res = PartialRes::new(Res::Local(self.self_param_id));
self.resolver.partial_res_map.insert(id, new_res);
}
}
}
impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
fn visit_path(&mut self, path: &'ast Path, id: NodeId) {
self.try_replace_id(id);
visit::walk_path(self, path);
}
fn visit_path_segment(&mut self, seg: &'ast PathSegment) {
self.try_replace_id(seg.id);
visit::walk_path_segment(self, seg);
}
}

View file

@ -1512,7 +1512,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
Some(hir::CoroutineKind::Coroutine(_)) => {
if !self.tcx.features().coroutines {
rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::coroutines,
span,
"yield syntax is experimental",
@ -1524,7 +1524,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
None => {
if !self.tcx.features().coroutines {
rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::coroutines,
span,
"yield syntax is experimental",

View file

@ -441,6 +441,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
hir::ItemKind::Macro(macro_def, macro_kind)
}
ItemKind::Delegation(box delegation) => {
let delegation_results = self.lower_delegation(delegation, id);
hir::ItemKind::Fn(
delegation_results.sig,
delegation_results.generics,
delegation_results.body_id,
)
}
ItemKind::MacCall(..) => {
panic!("`TyMac` should have been expanded by now")
}
@ -805,6 +813,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
(generics, kind, ty.is_some())
}
AssocItemKind::Delegation(box delegation) => {
let delegation_results = self.lower_delegation(delegation, i.id);
let item_kind = hir::TraitItemKind::Fn(
delegation_results.sig,
hir::TraitFn::Provided(delegation_results.body_id),
);
(delegation_results.generics, item_kind, true)
}
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
};
@ -826,6 +842,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
},
AssocItemKind::MacCall(..) => unimplemented!(),
};
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
@ -908,6 +927,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
)
}
AssocItemKind::Delegation(box delegation) => {
let delegation_results = self.lower_delegation(delegation, i.id);
(
delegation_results.generics,
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
)
}
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
};
@ -924,6 +950,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
let trait_item_def_id = self
.resolver
.get_partial_res(i.id)
.map(|r| r.expect_full_res().opt_def_id())
.unwrap_or(None);
self.is_in_trait_impl = trait_item_def_id.is_some();
hir::ImplItemRef {
id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
ident: self.lower_ident(i.ident),
@ -934,12 +967,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span),
},
AssocItemKind::MacCall(..) => unimplemented!(),
},
trait_item_def_id: self
.resolver
.get_partial_res(i.id)
.map(|r| r.expect_full_res().def_id()),
trait_item_def_id,
}
}

View file

@ -77,6 +77,7 @@ macro_rules! arena_vec {
mod asm;
mod block;
mod delegation;
mod errors;
mod expr;
mod format;
@ -1042,7 +1043,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
{
add_feature_diagnostics(
&mut err,
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::return_type_notation,
);
}
@ -2309,7 +2310,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span))
} else {
feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::generic_arg_infer,
c.value.span,
"using `_` for array lengths is unstable",

View file

@ -232,6 +232,9 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here
.trait = this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
.trait_impl = this impl is not `const`, so it cannot have `~const` trait bounds
.impl = inherent impls cannot have `~const` trait bounds
.trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `~const` trait bounds
.trait_impl_assoc_ty = associated types in non-const impls cannot have `~const` trait bounds
.inherent_assoc_ty = inherent associated types cannot have `~const` trait bounds
.object = trait objects cannot have `~const` trait bounds
.item = this item cannot have `~const` trait bounds

View file

@ -37,12 +37,17 @@ enum SelfSemantic {
}
/// What is the context that prevents using `~const`?
// FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're
// almost identical. This gets rid of an abstraction layer which might be considered bad.
enum DisallowTildeConstContext<'a> {
TraitObject,
Fn(FnKind<'a>),
Trait(Span),
TraitImpl(Span),
Impl(Span),
TraitAssocTy(Span),
TraitImplAssocTy(Span),
InherentAssocTy(Span),
Item,
}
@ -316,6 +321,7 @@ impl<'a> AstValidator<'a> {
constness: Const::No,
polarity: ImplPolarity::Positive,
trait_ref,
..
} = parent
{
Some(trait_ref.path.span.shrink_to_lo())
@ -1286,6 +1292,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
// suggestion for moving such bounds to the assoc const fns if available.
errors::TildeConstReason::Impl { span }
}
&DisallowTildeConstContext::TraitAssocTy(span) => {
errors::TildeConstReason::TraitAssocTy { span }
}
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
errors::TildeConstReason::TraitImplAssocTy { span }
}
&DisallowTildeConstContext::InherentAssocTy(span) => {
errors::TildeConstReason::InherentAssocTy { span }
}
DisallowTildeConstContext::TraitObject => {
errors::TildeConstReason::TraitObject
}
@ -1483,13 +1498,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_item_named(item.ident, "const");
}
let parent_is_const =
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
match &item.kind {
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
if self
.outer_trait_or_trait_impl
.as_ref()
.and_then(TraitOrTraitImpl::constness)
.is_some()
if parent_is_const
|| ctxt == AssocCtxt::Trait
|| matches!(sig.header.constness, Const::Yes(_)) =>
{
@ -1505,6 +1519,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
self.visit_fn(kind, item.span, item.id);
}
AssocItemKind::Type(_) => {
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
Some(TraitOrTraitImpl::Trait { .. }) => {
DisallowTildeConstContext::TraitAssocTy(item.span)
}
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
DisallowTildeConstContext::TraitImplAssocTy(item.span)
}
None => DisallowTildeConstContext::InherentAssocTy(item.span),
});
self.with_tilde_const(disallowed, |this| {
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
})
}
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
}
}

View file

@ -565,6 +565,8 @@ pub struct ConstBoundTraitObject {
pub span: Span,
}
// FIXME(effects): Consider making the note/reason the message of the diagnostic.
// FIXME(effects): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here).
#[derive(Diagnostic)]
#[diag(ast_passes_tilde_const_disallowed)]
pub struct TildeConstDisallowed {
@ -598,6 +600,21 @@ pub enum TildeConstReason {
#[primary_span]
span: Span,
},
#[note(ast_passes_trait_assoc_ty)]
TraitAssocTy {
#[primary_span]
span: Span,
},
#[note(ast_passes_trait_impl_assoc_ty)]
TraitImplAssocTy {
#[primary_span]
span: Span,
},
#[note(ast_passes_inherent_assoc_ty)]
InherentAssocTy {
#[primary_span]
span: Span,
},
#[note(ast_passes_object)]
TraitObject,
#[note(ast_passes_item)]

View file

@ -17,14 +17,12 @@ use crate::errors;
macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain).emit();
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
}
}};
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain)
.with_help($help)
.emit();
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
}
}};
}
@ -33,7 +31,7 @@ macro_rules! gate {
macro_rules! gate_alt {
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
feature_err(&$visitor.sess.parse_sess, $name, $span, $explain).emit();
feature_err(&$visitor.sess, $name, $span, $explain).emit();
}
}};
}
@ -45,7 +43,7 @@ macro_rules! gate_multi {
let spans: Vec<_> =
$spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
if !spans.is_empty() {
feature_err(&$visitor.sess.parse_sess, sym::$feature, spans, $explain).emit();
feature_err(&$visitor.sess, sym::$feature, spans, $explain).emit();
}
}
}};
@ -55,7 +53,7 @@ macro_rules! gate_multi {
macro_rules! gate_legacy {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
feature_warn(&$visitor.sess.parse_sess, sym::$feature, $span, $explain);
feature_warn(&$visitor.sess, sym::$feature, $span, $explain);
}
}};
}
@ -91,14 +89,7 @@ impl<'a> PostExpansionVisitor<'a> {
match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) {
Ok(()) => (),
Err(abi::AbiDisabled::Unstable { feature, explain }) => {
feature_err_issue(
&self.sess.parse_sess,
feature,
span,
GateIssue::Language,
explain,
)
.emit();
feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit();
}
Err(abi::AbiDisabled::Unrecognized) => {
if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
@ -556,6 +547,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(explicit_tail_calls, "`become` expression is experimental");
gate_all!(generic_const_items, "generic const items are experimental");
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
if !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::never_patterns) {
@ -570,13 +562,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
if let Ok(snippet) = sm.span_to_snippet(span)
&& snippet == "!"
{
feature_err(
&sess.parse_sess,
sym::never_patterns,
span,
"`!` patterns are experimental",
)
.emit();
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
.emit();
} else {
let suggestion = span.shrink_to_hi();
sess.dcx().emit_err(errors::MatchArmWithNoBody { span, suggestion });

View file

@ -376,6 +376,9 @@ impl<'a> State<'a> {
state.print_visibility(&item.vis)
});
}
ast::ItemKind::Delegation(box delegation) => {
self.print_delegation(delegation, &item.vis, &item.attrs)
}
}
self.ann.post(self, AnnNode::Item(item))
}
@ -554,10 +557,38 @@ impl<'a> State<'a> {
self.word(";");
}
}
ast::AssocItemKind::Delegation(box delegation) => {
self.print_delegation(delegation, vis, &item.attrs)
}
}
self.ann.post(self, AnnNode::SubItem(id))
}
pub(crate) fn print_delegation(
&mut self,
delegation: &ast::Delegation,
vis: &ast::Visibility,
attrs: &[ast::Attribute],
) {
if delegation.body.is_some() {
self.head("");
}
self.print_visibility(vis);
self.word_space("reuse");
if let Some(qself) = &delegation.qself {
self.print_qpath(&delegation.path, qself, false);
} else {
self.print_path(&delegation.path, false, 0);
}
if let Some(body) = &delegation.body {
self.nbsp();
self.print_block_with_attrs(body, attrs);
} else {
self.word(";");
}
}
fn print_fn_full(
&mut self,
sig: &ast::FnSig,

View file

@ -9,7 +9,7 @@ use rustc_macros::HashStable_Generic;
use rustc_session::config::ExpectedValues;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::parse::feature_err;
use rustc_session::{RustcVersion, Session};
use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
@ -518,15 +518,15 @@ pub struct Condition {
/// Tests if a cfg-pattern matches the cfg set
pub fn cfg_matches(
cfg: &ast::MetaItem,
sess: &ParseSess,
sess: &Session,
lint_node_id: NodeId,
features: Option<&Features>,
) -> bool {
eval_condition(cfg, sess, features, &mut |cfg| {
try_gate_cfg(cfg.name, cfg.span, sess, features);
match sess.check_config.expecteds.get(&cfg.name) {
match sess.parse_sess.check_config.expecteds.get(&cfg.name) {
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
sess.buffer_lint_with_diagnostic(
sess.parse_sess.buffer_lint_with_diagnostic(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
@ -541,8 +541,8 @@ pub fn cfg_matches(
),
);
}
None if sess.check_config.exhaustive_names => {
sess.buffer_lint_with_diagnostic(
None if sess.parse_sess.check_config.exhaustive_names => {
sess.parse_sess.buffer_lint_with_diagnostic(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
@ -555,18 +555,18 @@ pub fn cfg_matches(
}
_ => { /* not unexpected */ }
}
sess.config.contains(&(cfg.name, cfg.value))
sess.parse_sess.config.contains(&(cfg.name, cfg.value))
})
}
fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) {
fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) {
let gate = find_gated_cfg(|sym| sym == name);
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
gate_cfg(gated_cfg, span, sess, feats);
}
}
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
let explain = format!("`cfg({cfg})` is experimental and subject to change");
@ -594,11 +594,11 @@ fn parse_version(s: Symbol) -> Option<RustcVersion> {
/// evaluate individual items.
pub fn eval_condition(
cfg: &ast::MetaItem,
sess: &ParseSess,
sess: &Session,
features: Option<&Features>,
eval: &mut impl FnMut(Condition) -> bool,
) -> bool {
let dcx = &sess.dcx;
let dcx = &sess.parse_sess.dcx;
match &cfg.kind {
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
try_gate_cfg(sym::version, cfg.span, sess, features);
@ -626,7 +626,7 @@ pub fn eval_condition(
};
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
if sess.assume_incomplete_release {
if sess.parse_sess.assume_incomplete_release {
RustcVersion::CURRENT > min_version
} else {
RustcVersion::CURRENT >= min_version

View file

@ -22,7 +22,7 @@ pub fn expand_cfg(
Ok(cfg) => {
let matches_cfg = attr::cfg_matches(
&cfg,
&cx.sess.parse_sess,
&cx.sess,
cx.current_expansion.lint_node_id,
Some(cx.ecfg.features),
);

View file

@ -107,7 +107,7 @@ pub fn expand_include<'cx>(
return DummyResult::any(sp);
};
// The file will be added to the code map by the parser
let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) {
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
Err(err) => {
err.emit();
@ -179,7 +179,7 @@ pub fn expand_include_str(
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
return DummyResult::any(sp);
};
let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) {
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
Err(err) => {
err.emit();
@ -213,7 +213,7 @@ pub fn expand_include_bytes(
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
return DummyResult::any(sp);
};
let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) {
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
Err(err) => {
err.emit();

View file

@ -267,9 +267,12 @@ impl CguReuseTracker {
fn check_expected_reuse(&self, sess: &Session) {
if let Some(ref data) = self.data {
for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in
&data.expected_reuse
{
let mut keys = data.expected_reuse.keys().collect::<Vec<_>>();
keys.sort_unstable();
for cgu_name in keys {
let &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind) =
data.expected_reuse.get(cgu_name).unwrap();
if let Some(&actual_reuse) = data.actual_reuse.get(cgu_name) {
let (error, at_least) = match comparison_kind {
ComparisonKind::Exact => (expected_reuse != actual_reuse, false),

View file

@ -554,6 +554,11 @@ fn link_staticlib<'a>(
archive_builder_builder
.extract_bundled_libs(path, tempdir.as_ref(), &relevant_libs)
.unwrap_or_else(|e| sess.dcx().emit_fatal(e));
// We sort the libraries below
#[allow(rustc::potential_query_instability)]
let mut relevant_libs: Vec<Symbol> = relevant_libs.into_iter().collect();
relevant_libs.sort_unstable();
for filename in relevant_libs {
let joined = tempdir.as_ref().join(filename.as_str());
let path = joined.as_path();
@ -2201,14 +2206,19 @@ fn linker_with_args<'a>(
.iter()
.find(|(ty, _)| *ty == crate_type)
.expect("failed to find crate type in dependency format list");
let native_libraries_from_nonstatics = codegen_results
// We sort the libraries below
#[allow(rustc::potential_query_instability)]
let mut native_libraries_from_nonstatics = codegen_results
.crate_info
.native_libraries
.iter()
.filter_map(|(cnum, libraries)| {
(dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then_some(libraries)
})
.flatten();
.flatten()
.collect::<Vec<_>>();
native_libraries_from_nonstatics.sort_unstable_by(|a, b| a.name.as_str().cmp(b.name.as_str()));
for (raw_dylib_name, raw_dylib_imports) in
collate_raw_dylibs(sess, native_libraries_from_nonstatics)?
{
@ -2860,7 +2870,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
match lib.cfg {
Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),
Some(ref cfg) => rustc_attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
None => true,
}
}

View file

@ -319,6 +319,8 @@ fn exported_symbols_provider_local(
let (_, cgus) = tcx.collect_and_partition_mono_items(());
// The symbols created in this loop are sorted below it
#[allow(rustc::potential_query_instability)]
for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) {
if data.linkage != Linkage::External {
// We can only re-use things with external linkage, otherwise

View file

@ -912,17 +912,22 @@ impl CrateInfo {
})
.collect();
let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" };
// This loop only adds new items to values of the hash map, so the order in which we
// iterate over the values is not important.
#[allow(rustc::potential_query_instability)]
info.linked_symbols
.iter_mut()
.filter(|(crate_type, _)| {
!matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
})
.for_each(|(_, linked_symbols)| {
linked_symbols.extend(
missing_weak_lang_items
.iter()
.map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)),
);
let mut symbols = missing_weak_lang_items
.iter()
.map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text))
.collect::<Vec<_>>();
symbols.sort_unstable_by(|a, b| a.0.cmp(&b.0));
linked_symbols.extend(symbols);
if tcx.allocator_kind(()).is_some() {
// At least one crate needs a global allocator. This crate may be placed
// after the crate that defines it in the linker order, in which case some

View file

@ -155,7 +155,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
Some([item]) if item.has_name(sym::linker) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::used_with_arg,
attr.span,
"`#[used(linker)]` is currently unstable",
@ -167,7 +167,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
Some([item]) if item.has_name(sym::compiler) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::used_with_arg,
attr.span,
"`#[used(compiler)]` is currently unstable",
@ -251,7 +251,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
&& !attr.span.allows_unstable(sym::closure_track_caller)
{
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::closure_track_caller,
attr.span,
"`#[track_caller]` on closures is currently unstable",
@ -304,7 +304,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// `#[target_feature]` on `main` and `start`.
} else if !tcx.features().target_feature_11 {
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::target_feature_11,
attr.span,
"`#[target_feature(..)]` can only be applied to `unsafe` functions",

View file

@ -11,7 +11,6 @@
#![feature(strict_provenance)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
//! The backend-agnostic functions of this crate use functions defined in various traits that

View file

@ -82,7 +82,7 @@ pub fn from_target_feature(
};
if !allowed {
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
feature_gate.unwrap(),
item.span(),
format!("the target feature `{feature}` is currently unstable"),

View file

@ -64,7 +64,7 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
&ccx.tcx.sess,
sym::const_fn_floating_point_arithmetic,
span,
format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
@ -553,7 +553,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
&ccx.tcx.sess,
sym::const_mut_refs,
span,
format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
@ -624,7 +624,7 @@ pub mod ty {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
&ccx.tcx.sess,
sym::const_mut_refs,
span,
format!("mutable references are not allowed in {}s", ccx.const_kind()),

View file

@ -865,10 +865,6 @@ impl DiagCtxt {
/// directly).
#[track_caller]
pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug();
if treat_next_err_as_bug {
self.bug(msg);
}
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
.emit()
}
@ -883,10 +879,6 @@ impl DiagCtxt {
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug();
if treat_next_err_as_bug {
self.span_bug(sp, msg);
}
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
.with_span(sp)
.emit()
@ -1259,10 +1251,6 @@ impl DiagCtxtInner {
}
fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() {
diagnostic.level = Bug;
}
// The `LintExpectationId` can be stable or unstable depending on when it was created.
// Diagnostics created before the definition of `HirId`s are unstable and can not yet
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
@ -1298,6 +1286,12 @@ impl DiagCtxtInner {
_ => {}
}
// This must come after the possible promotion of `DelayedBug` to
// `Error` above.
if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() {
diagnostic.level = Bug;
}
if diagnostic.has_future_breakage() {
// Future breakages aren't emitted if they're Level::Allow,
// but they still need to be constructed and stashed below,
@ -1387,20 +1381,14 @@ impl DiagCtxtInner {
}
fn treat_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count + self.lint_err_count + self.delayed_bug_count() >= c.get()
})
self.flags.treat_err_as_bug.is_some_and(|c| self.err_count + self.lint_err_count >= c.get())
}
// Use this one before incrementing `err_count`.
fn treat_next_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
})
}
fn delayed_bug_count(&self) -> usize {
self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len()
self.flags
.treat_err_as_bug
.is_some_and(|c| self.err_count + self.lint_err_count + 1 >= c.get())
}
fn has_errors(&self) -> bool {
@ -1412,7 +1400,7 @@ impl DiagCtxtInner {
}
fn flush_delayed(&mut self, kind: DelayedBugKind) {
let (bugs, explanation) = match kind {
let (bugs, note1) = match kind {
DelayedBugKind::Normal => (
std::mem::take(&mut self.span_delayed_bugs),
"no errors encountered even though `span_delayed_bug` issued",
@ -1422,6 +1410,7 @@ impl DiagCtxtInner {
"no warnings or errors encountered even though `good_path_delayed_bugs` issued",
),
};
let note2 = "those delayed bugs will now be shown as internal compiler errors";
if bugs.is_empty() {
return;
@ -1447,8 +1436,11 @@ impl DiagCtxtInner {
if i == 0 {
// Put the overall explanation before the `DelayedBug`s, to
// frame them better (e.g. separate warnings from them).
self.emit_diagnostic(Diagnostic::new(Bug, explanation));
// frame them better (e.g. separate warnings from them). Also,
// make it a note so it doesn't count as an error, because that
// could trigger `-Ztreat-err-as-bug`, which we don't want.
self.emit_diagnostic(Diagnostic::new(Note, note1));
self.emit_diagnostic(Diagnostic::new(Note, note2));
}
let mut bug =
@ -1474,22 +1466,12 @@ impl DiagCtxtInner {
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
match (
self.err_count + self.lint_err_count,
self.delayed_bug_count(),
self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(),
) {
(1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
(0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"),
(count, delayed_count, val) => {
if delayed_count > 0 {
panic!(
"aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={val}`",
)
} else {
panic!("aborting after {count} errors due to `-Z treat-err-as-bug={val}`")
}
}
let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
assert_eq!(n, self.err_count + self.lint_err_count);
if n == 1 {
panic!("aborting due to `-Z treat-err-as-bug=1`");
} else {
panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
}
}
}

View file

@ -1150,7 +1150,7 @@ impl<'a> ExtCtxt<'a> {
///
/// This unifies the logic used for resolving `include_X!`.
pub fn resolve_path(
parse_sess: &ParseSess,
parse_sess: &Session,
path: impl Into<PathBuf>,
span: Span,
) -> PResult<'_, PathBuf> {
@ -1166,7 +1166,7 @@ pub fn resolve_path(
.expect("attempting to resolve a file path in an external file"),
FileName::DocTest(path, _) => path,
other => {
return Err(parse_sess.dcx.create_err(errors::ResolveRelativePath {
return Err(parse_sess.dcx().create_err(errors::ResolveRelativePath {
span,
path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(),
}));
@ -1390,7 +1390,7 @@ pub fn parse_macro_name_and_helper_attrs(
/// asserts in old versions of those crates and their wide use in the ecosystem.
/// See issue #73345 for more details.
/// FIXME(#73933): Remove this eventually.
fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
let name = item.ident.name;
if name == sym::ProceduralMasqueradeDummyType {
if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
@ -1418,7 +1418,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
};
if crate_matches {
sess.buffer_lint_with_diagnostic(
sess.parse_sess.buffer_lint_with_diagnostic(
PROC_MACRO_BACK_COMPAT,
item.ident.span,
ast::CRATE_NODE_ID,
@ -1439,7 +1439,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
false
}
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &ParseSess) -> bool {
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) -> bool {
let item = match ann {
Annotatable::Item(item) => item,
Annotatable::Stmt(stmt) => match &stmt.kind {
@ -1451,7 +1451,7 @@ pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &P
pretty_printing_compatibility_hack(item, sess)
}
pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &ParseSess) -> bool {
pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) -> bool {
let item = match nt {
Nonterminal::NtItem(item) => item,
Nonterminal::NtStmt(stmt) => match &stmt.kind {

View file

@ -256,12 +256,7 @@ impl<'a> StripUnconfigured<'a> {
);
}
if !attr::cfg_matches(
&cfg_predicate,
&self.sess.parse_sess,
self.lint_node_id,
self.features,
) {
if !attr::cfg_matches(&cfg_predicate, &self.sess, self.lint_node_id, self.features) {
return vec![];
}
@ -369,12 +364,7 @@ impl<'a> StripUnconfigured<'a> {
};
(
parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| {
attr::cfg_matches(
meta_item,
&self.sess.parse_sess,
self.lint_node_id,
self.features,
)
attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features)
}),
Some(meta_item),
)
@ -385,7 +375,7 @@ impl<'a> StripUnconfigured<'a> {
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if self.features.is_some_and(|features| !features.stmt_expr_attributes) {
let mut err = feature_err(
&self.sess.parse_sess,
&self.sess,
sym::stmt_expr_attributes,
attr.span,
"attributes on expressions are experimental",

View file

@ -30,8 +30,8 @@ use rustc_parse::parser::{
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Limit;
use rustc_session::parse::feature_err;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Ident};
use rustc_span::{FileName, LocalExpnId, Span};
@ -800,7 +800,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
return;
}
feature_err(
&self.cx.sess.parse_sess,
&self.cx.sess,
sym::proc_macro_hygiene,
span,
format!("custom attributes cannot be applied to {kind}"),
@ -810,7 +810,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
fn gate_proc_macro_input(&self, annotatable: &Annotatable) {
struct GateProcMacroInput<'a> {
parse_sess: &'a ParseSess,
sess: &'a Session,
}
impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
@ -820,7 +820,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
{
feature_err(
self.parse_sess,
self.sess,
sym::proc_macro_hygiene,
item.span,
"non-inline modules in proc macro input are unstable",
@ -835,8 +835,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
if !self.cx.ecfg.features.proc_macro_hygiene {
annotatable
.visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess });
annotatable.visit_with(&mut GateProcMacroInput { sess: &self.cx.sess });
}
}

View file

@ -477,14 +477,14 @@ pub fn compile_declarative_macro(
let tt = mbe::quoted::parse(
&TokenStream::new(vec![tt.clone()]),
true,
&sess.parse_sess,
sess,
def.id,
features,
edition,
)
.pop()
.unwrap();
valid &= check_lhs_nt_follows(&sess.parse_sess, def, &tt);
valid &= check_lhs_nt_follows(sess, def, &tt);
return tt;
}
sess.dcx().span_bug(def.span, "wrong-structured lhs")
@ -501,7 +501,7 @@ pub fn compile_declarative_macro(
return mbe::quoted::parse(
&TokenStream::new(vec![tt.clone()]),
false,
&sess.parse_sess,
sess,
def.id,
features,
edition,
@ -516,12 +516,12 @@ pub fn compile_declarative_macro(
};
for rhs in &rhses {
valid &= check_rhs(&sess.parse_sess, rhs);
valid &= check_rhs(sess, rhs);
}
// don't abort iteration early, so that errors for multiple lhses can be reported
for lhs in &lhses {
valid &= check_lhs_no_empty_seq(&sess.parse_sess, slice::from_ref(lhs));
valid &= check_lhs_no_empty_seq(sess, slice::from_ref(lhs));
}
valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses);
@ -588,21 +588,21 @@ pub fn compile_declarative_macro(
(mk_syn_ext(expander), rule_spans)
}
fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
fn check_lhs_nt_follows(sess: &Session, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
// lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
if let mbe::TokenTree::Delimited(.., delimited) = lhs {
check_matcher(sess, def, &delimited.tts)
} else {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
sess.dcx.span_err(lhs.span(), msg);
sess.dcx().span_err(lhs.span(), msg);
false
}
// we don't abort on errors on rejection, the driver will do that for us
// after parsing/expansion. we can report every error in every macro this way.
}
fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool {
fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
if seq.separator.is_some() {
false
} else {
@ -621,7 +621,7 @@ fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool
iter.next();
}
let span = t.span.to(now.span);
sess.dcx.span_note(span, "doc comments are ignored in matcher position");
sess.dcx().span_note(span, "doc comments are ignored in matcher position");
}
mbe::TokenTree::Sequence(_, sub_seq)
if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
@ -635,7 +635,7 @@ fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool
/// Checks that the lhs contains no repetition which could match an empty token
/// tree, because then the matcher would hang indefinitely.
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> bool {
use mbe::TokenTree;
for tt in tts {
match tt {
@ -651,7 +651,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
TokenTree::Sequence(span, seq) => {
if is_empty_token_tree(sess, seq) {
let sp = span.entire();
sess.dcx.span_err(sp, "repetition matches empty token tree");
sess.dcx().span_err(sp, "repetition matches empty token tree");
return false;
}
if !check_lhs_no_empty_seq(sess, &seq.tts) {
@ -664,22 +664,22 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
true
}
fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> bool {
match *rhs {
mbe::TokenTree::Delimited(..) => return true,
_ => {
sess.dcx.span_err(rhs.span(), "macro rhs must be delimited");
sess.dcx().span_err(rhs.span(), "macro rhs must be delimited");
}
}
false
}
fn check_matcher(sess: &ParseSess, def: &ast::Item, matcher: &[mbe::TokenTree]) -> bool {
fn check_matcher(sess: &Session, def: &ast::Item, matcher: &[mbe::TokenTree]) -> bool {
let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty();
let err = sess.dcx.err_count();
let err = sess.dcx().err_count();
check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix);
err == sess.dcx.err_count()
err == sess.dcx().err_count()
}
fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
@ -1014,7 +1014,7 @@ impl<'tt> TokenSet<'tt> {
// Requires that `first_sets` is pre-computed for `matcher`;
// see `FirstSets::new`.
fn check_matcher_core<'tt>(
sess: &ParseSess,
sess: &Session,
def: &ast::Item,
first_sets: &FirstSets<'tt>,
matcher: &'tt [mbe::TokenTree],
@ -1139,7 +1139,7 @@ fn check_matcher_core<'tt>(
name,
Some(NonterminalKind::PatParam { inferred: false }),
));
sess.buffer_lint_with_diagnostic(
sess.parse_sess.buffer_lint_with_diagnostic(
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
span,
ast::CRATE_NODE_ID,
@ -1158,7 +1158,7 @@ fn check_matcher_core<'tt>(
};
let sp = next_token.span();
let mut err = sess.dcx.struct_span_err(
let mut err = sess.dcx().struct_span_err(
sp,
format!(
"`${name}:{frag}` {may_be} followed by `{next}`, which \
@ -1172,7 +1172,7 @@ fn check_matcher_core<'tt>(
err.span_label(sp, format!("not allowed after `{kind}` fragments"));
if kind == NonterminalKind::PatWithOr
&& sess.edition.at_least_rust_2021()
&& sess.parse_sess.edition.at_least_rust_2021()
&& next_token.is_token(&BinOp(token::BinOpToken::Or))
{
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(

View file

@ -5,7 +5,8 @@ use rustc_ast::token::{self, Delimiter, Token};
use rustc_ast::{tokenstream, NodeId};
use rustc_ast_pretty::pprust;
use rustc_feature::Features;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::edition::Edition;
@ -38,7 +39,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
pub(super) fn parse(
input: &tokenstream::TokenStream,
parsing_patterns: bool,
sess: &ParseSess,
sess: &Session,
node_id: NodeId,
features: &Features,
edition: Edition,
@ -84,7 +85,7 @@ pub(super) fn parse(
"invalid fragment specifier `{}`",
frag.name
);
sess.dcx
sess.dcx()
.struct_span_err(span, msg)
.with_help(VALID_FRAGMENT_NAMES_MSG)
.emit();
@ -113,7 +114,7 @@ pub(super) fn parse(
}
/// Asks for the `macro_metavar_expr` feature if it is not already declared
fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess, span: Span) {
fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) {
if !features.macro_metavar_expr {
let msg = "meta-variable expressions are unstable";
feature_err(sess, sym::macro_metavar_expr, span, msg).emit();
@ -138,7 +139,7 @@ fn parse_tree<'a>(
tree: &'a tokenstream::TokenTree,
outer_trees: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
parsing_patterns: bool,
sess: &ParseSess,
sess: &Session,
node_id: NodeId,
features: &Features,
edition: Edition,
@ -174,7 +175,8 @@ fn parse_tree<'a>(
// The delimiter is `{`. This indicates the beginning
// of a meta-variable expression (e.g. `${count(ident)}`).
// Try to parse the meta-variable expression.
match MetaVarExpr::parse(tts, delim_span.entire(), sess) {
match MetaVarExpr::parse(tts, delim_span.entire(), &sess.parse_sess)
{
Err(err) => {
err.emit();
// Returns early the same read `$` to avoid spanning
@ -195,7 +197,7 @@ fn parse_tree<'a>(
_ => {
let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
let msg = format!("expected `(` or `{{`, found `{tok}`");
sess.dcx.span_err(delim_span.entire(), msg);
sess.dcx().span_err(delim_span.entire(), msg);
}
}
}
@ -244,7 +246,7 @@ fn parse_tree<'a>(
Some(tokenstream::TokenTree::Token(token, _)) => {
let msg =
format!("expected identifier, found `{}`", pprust::token_to_string(token),);
sess.dcx.span_err(token.span, msg);
sess.dcx().span_err(token.span, msg);
TokenTree::MetaVar(token.span, Ident::empty())
}
@ -313,7 +315,7 @@ fn parse_kleene_op<'a>(
fn parse_sep_and_kleene_op<'a>(
input: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
span: Span,
sess: &ParseSess,
sess: &Session,
) -> (Option<Token>, KleeneToken) {
// We basically look at two token trees here, denoted as #1 and #2 below
let span = match parse_kleene_op(input, span) {
@ -325,7 +327,7 @@ fn parse_sep_and_kleene_op<'a>(
// #2 is the `?` Kleene op, which does not take a separator (error)
Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
// Error!
sess.dcx.span_err(
sess.dcx().span_err(
token.span,
"the `?` macro repetition operator does not take a separator",
);
@ -346,7 +348,7 @@ fn parse_sep_and_kleene_op<'a>(
};
// If we ever get to this point, we have experienced an "unexpected token" error
sess.dcx.span_err(span, "expected one of: `*`, `+`, or `?`");
sess.dcx().span_err(span, "expected one of: `*`, `+`, or `?`");
// Return a dummy
(None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
@ -355,9 +357,10 @@ fn parse_sep_and_kleene_op<'a>(
// `$$` or a meta-variable is the lhs of a macro but shouldn't.
//
// For example, `macro_rules! foo { ( ${length()} ) => {} }`
fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &ParseSess, token: &Token) {
sess.dcx.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
sess.dcx.span_note(
fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &Session, token: &Token) {
sess.dcx()
.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
sess.dcx().span_note(
token.span,
"`$$` and meta-variable expressions are not allowed inside macro parameter definitions",
);

View file

@ -119,7 +119,7 @@ impl MultiItemModifier for DeriveProcMacro {
// We need special handling for statement items
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
let is_stmt = matches!(item, Annotatable::Stmt(..));
let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.parse_sess);
let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess);
let input = if hack {
let nt = match item {
Annotatable::Item(item) => token::NtItem(item),

View file

@ -258,7 +258,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
// represented as a delimited group.
// FIXME: It needs to be removed, but there are some
// compatibility issues (see #73345).
if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.sess()) {
if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.ecx.sess) {
trees.extend(Self::from_internal((stream, rustc)));
} else {
trees.push(TokenTree::Group(Group {

View file

@ -2571,9 +2571,17 @@ pub enum OpaqueTyOrigin {
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
pub enum InferDelegationKind {
Input(usize),
Output,
}
/// The various kinds of types recognized by the compiler.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir> {
/// Actual type should be inherited from `DefId` signature
InferDelegation(DefId, InferDelegationKind),
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
/// A fixed length array (i.e., `[T; n]`).

View file

@ -856,7 +856,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
visitor.visit_lifetime(lifetime);
}
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::Err(_) => {}
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
}
}

View file

@ -263,6 +263,10 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
hir_analysis_not_supported_delegation =
{$descr} is not supported yet
.label = callee defined here
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait

View file

@ -59,7 +59,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar {
// For now, require that parenthetical notation be used only with `Fn()` etc.
feature_err(
&self.tcx().sess.parse_sess,
&self.tcx().sess,
sym::unboxed_closures,
span,
"parenthetical notation is only stable when used with `Fn`-family traits",
@ -75,7 +75,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if trait_segment.args().parenthesized != hir::GenericArgsParentheses::ParenSugar {
// For now, require that parenthetical notation be used only with `Fn()` etc.
let mut err = feature_err(
&sess.parse_sess,
sess,
sym::unboxed_closures,
span,
"the precise format of `Fn`-family traits' type parameters is subject to change",

View file

@ -29,10 +29,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, ParamEnv, Ty, TyCtxt,
TypeVisitableExt,
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty,
TyCtxt, TypeVisitableExt,
};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
@ -2322,6 +2321,114 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.ast_ty_to_ty_inner(ast_ty, false, true)
}
fn check_delegation_constraints(&self, sig_id: DefId, span: Span, emit: bool) -> bool {
let mut error_occured = false;
let sig_span = self.tcx().def_span(sig_id);
let mut try_emit = |descr| {
if emit {
self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation {
span,
descr,
callee_span: sig_span,
});
}
error_occured = true;
};
if let Some(node) = self.tcx().hir().get_if_local(sig_id)
&& let Some(decl) = node.fn_decl()
&& let hir::FnRetTy::Return(ty) = decl.output
&& let hir::TyKind::InferDelegation(_, _) = ty.kind
{
try_emit("recursive delegation");
}
let sig = self.tcx().fn_sig(sig_id).instantiate_identity();
if sig.output().has_opaque_types() {
try_emit("delegation to a function with opaque type");
}
let sig_generics = self.tcx().generics_of(sig_id);
let parent = self.tcx().parent(self.item_def_id());
let parent_generics = self.tcx().generics_of(parent);
let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
let sig_has_self = sig_generics.has_self as usize;
if sig_generics.count() > sig_has_self || parent_generics.count() > parent_is_trait {
try_emit("delegation with early bound generics");
}
if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes {
try_emit("delegation to async functions");
}
if self.tcx().constness(sig_id) == hir::Constness::Const {
try_emit("delegation to const functions");
}
if sig.c_variadic() {
try_emit("delegation to variadic functions");
// variadic functions are also `unsafe` and `extern "C"`.
// Do not emit same error multiple times.
return error_occured;
}
if let hir::Unsafety::Unsafe = sig.unsafety() {
try_emit("delegation to unsafe functions");
}
if abi::Abi::Rust != sig.abi() {
try_emit("delegation to non Rust ABI functions");
}
error_occured
}
fn ty_from_delegation(
&self,
sig_id: DefId,
idx: hir::InferDelegationKind,
span: Span,
) -> Ty<'tcx> {
if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output)
{
let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case");
self.set_tainted_by_errors(e);
return Ty::new_error(self.tcx(), e);
};
let sig = self.tcx().fn_sig(sig_id);
let sig_generics = self.tcx().generics_of(sig_id);
let parent = self.tcx().parent(self.item_def_id());
let parent_def_kind = self.tcx().def_kind(parent);
let sig = if let DefKind::Impl { .. } = parent_def_kind
&& sig_generics.has_self
{
// Generic params can't be here except the trait self type.
// They are not supported yet.
assert_eq!(sig_generics.count(), 1);
assert_eq!(self.tcx().generics_of(parent).count(), 0);
let self_ty = self.tcx().type_of(parent).instantiate_identity();
let generic_self_ty = ty::GenericArg::from(self_ty);
let substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
sig.instantiate(self.tcx(), substs)
} else {
sig.instantiate_identity()
};
// Bound vars are also inherited from `sig_id`. They will be
// rebinded later in `ty_of_fn`.
let sig = sig.skip_binder();
match idx {
hir::InferDelegationKind::Input(id) => sig.inputs()[id],
hir::InferDelegationKind::Output => sig.output(),
}
}
/// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
/// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
#[instrument(level = "debug", skip(self), ret)]
@ -2329,6 +2436,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let result_ty = match &ast_ty.kind {
hir::TyKind::InferDelegation(sig_id, idx) => {
self.ty_from_delegation(*sig_id, *idx, ast_ty.span)
}
hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)),
hir::TyKind::Ptr(mt) => {
Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
@ -2520,7 +2630,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir_ty: Option<&hir::Ty<'_>>,
) -> ty::PolyFnSig<'tcx> {
let tcx = self.tcx();
let bound_vars = tcx.late_bound_vars(hir_id);
let bound_vars = if let hir::FnRetTy::Return(ret_ty) = decl.output
&& let hir::TyKind::InferDelegation(sig_id, _) = ret_ty.kind
{
tcx.fn_sig(sig_id).skip_binder().bound_vars()
} else {
tcx.late_bound_vars(hir_id)
};
debug!(?bound_vars);
// We proactively collect all the inferred type params to emit a single error per fn def.
@ -2543,7 +2659,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{
infer_replacements.push((a.span, suggested_ty.to_string()));
return suggested_ty;
return Ty::new_error_with_message(
self.tcx(),
a.span,
suggested_ty.to_string(),
);
}
}
@ -2561,7 +2681,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
{
infer_replacements.push((output.span, suggested_ty.to_string()));
suggested_ty
Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string())
} else {
visitor.visit_ty(output);
self.ast_ty_to_ty(output)

View file

@ -996,7 +996,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
if adt.is_union() && !tcx.features().transparent_unions {
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::transparent_unions,
tcx.def_span(adt.did()),
"transparent unions are unstable",
@ -1128,7 +1128,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
if !tcx.features().repr128 {
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::repr128,
tcx.def_span(def_id),
"repr with 128-bit type is unstable",

View file

@ -293,7 +293,7 @@ fn default_body_is_unstable(
rustc_session::parse::add_feature_diagnostics_for_issue(
&mut err,
&tcx.sess.parse_sess,
&tcx.sess,
feature,
rustc_feature::GateIssue::Library(issue),
false,

View file

@ -1591,7 +1591,7 @@ fn check_method_receiver<'tcx>(
return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; would have worked with `arbitrary_self_types`.
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::arbitrary_self_types,
span,
format!(

View file

@ -1189,12 +1189,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.ident.span,
"anonymous lifetimes in `impl Trait` are unstable",
);
let mut diag: rustc_errors::DiagnosticBuilder<'_> =
rustc_session::parse::feature_err(
&self.tcx.sess,
sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.ident.span,
"anonymous lifetimes in `impl Trait` are unstable",
);
if let Some(generics) =
self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)

View file

@ -639,7 +639,7 @@ fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::inherent_associated_types,
span,
"inherent associated types are unstable",

View file

@ -1501,3 +1501,13 @@ pub enum RefOfMutStaticSugg {
var: String,
},
}
#[derive(Diagnostic)]
#[diag(hir_analysis_not_supported_delegation)]
pub struct NotSupportedDelegation<'a> {
#[primary_span]
pub span: Span,
pub descr: &'a str,
#[label]
pub callee_span: Span,
}

View file

@ -116,7 +116,8 @@ use rustc_hir::def::DefKind;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`";
const CONVENTIONS_UNSTABLE: &str =
"`C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`";
const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
const UNSTABLE_EXPLAIN: &str =
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
@ -133,13 +134,8 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
// Using this ABI would be ok, if the feature for additional ABI support was enabled.
// Return CONVENTIONS_STABLE, because we want the other error to look the same.
(false, true) => {
feature_err(
&tcx.sess.parse_sess,
sym::extended_varargs_abi_support,
span,
UNSTABLE_EXPLAIN,
)
.emit();
feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, UNSTABLE_EXPLAIN)
.emit();
CONVENTIONS_STABLE
}

View file

@ -320,7 +320,7 @@ impl<'a> State<'a> {
self.word("/*ERROR*/");
self.pclose();
}
hir::TyKind::Infer => {
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
self.word("_");
}
}

View file

@ -704,7 +704,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::unsized_tuple_coercion,
self.cause.span,
"unsized tuple coercion is not stable enough for use and is subject to change",

View file

@ -1865,7 +1865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt);
if self.tcx.sess.is_nightly_build() && same_adt {
feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::type_changing_struct_update,
base_expr.span,
"type changing struct updating is experimental",
@ -3262,7 +3262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !self.tcx.features().offset_of_enum {
rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::offset_of_enum,
ident.span,
"using enums in offset_of is experimental",

View file

@ -84,7 +84,7 @@ impl<'tcx> InferCtxt<'tcx> {
selection_cache: self.selection_cache.clone(),
evaluation_cache: self.evaluation_cache.clone(),
reported_trait_errors: self.reported_trait_errors.clone(),
reported_closure_mismatch: self.reported_closure_mismatch.clone(),
reported_signature_mismatch: self.reported_signature_mismatch.clone(),
tainted_by_errors: self.tainted_by_errors.clone(),
err_count_on_creation: self.err_count_on_creation,
universe: self.universe.clone(),

View file

@ -278,7 +278,7 @@ pub struct InferCtxt<'tcx> {
/// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FxIndexMap<Span, Vec<ty::Predicate<'tcx>>>>,
pub reported_closure_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
/// When an error occurs, we want to avoid reporting "derived"
/// errors that are due to this original failure. Normally, we
@ -702,7 +702,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
selection_cache: Default::default(),
evaluation_cache: Default::default(),
reported_trait_errors: Default::default(),
reported_closure_mismatch: Default::default(),
reported_signature_mismatch: Default::default(),
tainted_by_errors: Cell::new(None),
err_count_on_creation: tcx.dcx().err_count(),
universe: Cell::new(ty::UniverseIndex::ROOT),

View file

@ -202,8 +202,15 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
if !args.is_empty() {
error!("`any()` must be empty");
}
} else if arg.has_name(sym::none)
&& let Some(args) = arg.meta_item_list()
{
values.insert(None);
if !args.is_empty() {
error!("`none()` must be empty");
}
} else {
error!("`values()` arguments must be string literals or `any()`");
error!("`values()` arguments must be string literals, `none()` or `any()`");
}
}
} else {

View file

@ -1306,10 +1306,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
cx.emit_spanned_lint(
UNGATED_ASYNC_FN_TRACK_CALLER,
attr.span,
BuiltinUngatedAsyncFnTrackCaller {
label: span,
parse_sess: &cx.tcx.sess.parse_sess,
},
BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },
);
}
}

View file

@ -786,7 +786,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
if let ast::LitKind::Str(rationale, _) = name_value.kind {
if !self.features.lint_reasons {
feature_err(
&self.sess.parse_sess,
&self.sess,
sym::lint_reasons,
item.span,
"lint reasons are experimental",
@ -1074,7 +1074,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
lint.note(fluent::lint_note);
rustc_session::parse::add_feature_diagnostics_for_issue(
lint,
&self.sess.parse_sess,
&self.sess,
feature,
GateIssue::Language,
lint_from_cli,

View file

@ -13,7 +13,7 @@ use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{
inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
};
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
use crate::{
@ -235,7 +235,7 @@ pub struct BuiltinUnstableFeatures;
// lint_ungated_async_fn_track_caller
pub struct BuiltinUngatedAsyncFnTrackCaller<'a> {
pub label: Span,
pub parse_sess: &'a ParseSess,
pub session: &'a Session,
}
impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
@ -243,7 +243,7 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
diag.span_label(self.label, fluent::lint_label);
rustc_session::parse::add_feature_diagnostics(
diag,
self.parse_sess,
self.session,
sym::async_fn_track_caller,
);
}

View file

@ -82,7 +82,7 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib>
pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
match lib.cfg {
Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),
Some(ref cfg) => attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
None => true,
}
}
@ -163,7 +163,7 @@ impl<'tcx> Collector<'tcx> {
"link-arg" => {
if !features.link_arg_attribute {
feature_err(
&sess.parse_sess,
sess,
sym::link_arg_attribute,
span,
"link kind `link-arg` is unstable",
@ -206,13 +206,8 @@ impl<'tcx> Collector<'tcx> {
continue;
};
if !features.link_cfg {
feature_err(
&sess.parse_sess,
sym::link_cfg,
item.span(),
"link cfg is unstable",
)
.emit();
feature_err(sess, sym::link_cfg, item.span(), "link cfg is unstable")
.emit();
}
cfg = Some(link_cfg.clone());
}
@ -277,7 +272,7 @@ impl<'tcx> Collector<'tcx> {
macro report_unstable_modifier($feature: ident) {
if !features.$feature {
feature_err(
&sess.parse_sess,
sess,
sym::$feature,
span,
format!("linking modifier `{modifier}` is unstable"),
@ -520,11 +515,23 @@ impl<'tcx> Collector<'tcx> {
) -> DllImport {
let span = self.tcx.def_span(item);
// this logic is similar to `Target::adjust_abi` (in rustc_target/src/spec/mod.rs) but errors on unsupported inputs
let calling_convention = if self.tcx.sess.target.arch == "x86" {
match abi {
Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
Abi::Stdcall { .. } | Abi::System { .. } => {
DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
Abi::Stdcall { .. } => DllCallingConvention::Stdcall(self.i686_arg_list_size(item)),
// On Windows, `extern "system"` behaves like msvc's `__stdcall`.
// `__stdcall` only applies on x86 and on non-variadic functions:
// https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
Abi::System { .. } => {
let c_variadic =
self.tcx.type_of(item).instantiate_identity().fn_sig(self.tcx).c_variadic();
if c_variadic {
DllCallingConvention::C
} else {
DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
}
}
Abi::Fastcall { .. } => {
DllCallingConvention::Fastcall(self.i686_arg_list_size(item))

View file

@ -116,8 +116,7 @@ pub fn report_unstable(
if is_soft {
soft_handler(SOFT_UNSTABLE, span, msg)
} else {
let mut err =
feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), msg);
let mut err = feature_err_issue(sess, feature, span, GateIssue::Library(issue), msg);
if let Some((inner_types, msg, sugg, applicability)) = suggestion {
err.span_suggestion(inner_types, msg, sugg, applicability);
}

View file

@ -611,9 +611,6 @@ pub enum SelectionError<'tcx> {
NotConstEvaluatable(NotConstEvaluatable),
/// Exceeded the recursion depth during type projection.
Overflow(OverflowError),
/// Signaling that an error has already been emitted, to avoid
/// multiple errors being shown.
ErrorReporting,
/// Computing an opaque type's hidden type caused an error (e.g. a cycle error).
/// We can thus not know whether the hidden type implements an auto trait, so
/// we should not presume anything about it.

View file

@ -302,7 +302,6 @@ impl EvaluationResult {
pub enum OverflowError {
Error(ErrorGuaranteed),
Canonical,
ErrorReporting,
}
impl From<ErrorGuaranteed> for OverflowError {
@ -318,7 +317,6 @@ impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
match overflow_error {
OverflowError::Error(e) => SelectionError::Overflow(OverflowError::Error(e)),
OverflowError::Canonical => SelectionError::Overflow(OverflowError::Canonical),
OverflowError::ErrorReporting => SelectionError::ErrorReporting,
}
}
}

View file

@ -42,7 +42,7 @@ use rustc_data_structures::unord::UnordMap;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet};
use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
@ -202,6 +202,10 @@ pub struct ResolverAstLowering {
/// Lints that were emitted by the resolver and early lints.
pub lint_buffer: Steal<LintBuffer>,
/// Information about functions signatures for delegation items expansion
pub has_self: LocalDefIdSet,
pub fn_parameter_counts: LocalDefIdMap<usize>,
}
#[derive(Clone, Copy, Debug)]

View file

@ -252,6 +252,8 @@ impl<'a> Parser<'a> {
{
// IMPL ITEM
self.parse_item_impl(attrs, def_())?
} else if self.is_reuse_path_item() {
self.parse_item_delegation()?
} else if self.check_keyword(kw::Mod)
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod])
{
@ -349,11 +351,18 @@ impl<'a> Parser<'a> {
/// When parsing a statement, would the start of a path be an item?
pub(super) fn is_path_start_item(&mut self) -> bool {
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|| self.is_reuse_path_item()
|| self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
|| matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
}
fn is_reuse_path_item(&mut self) -> bool {
// no: `reuse ::path` for compatibility reasons with macro invocations
self.token.is_keyword(kw::Reuse)
&& self.look_ahead(1, |t| t.is_path_start() && t.kind != token::ModSep)
}
/// Are we sure this could not possibly be a macro invocation?
fn isnt_macro_invocation(&mut self) -> bool {
self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::ModSep)
@ -655,6 +664,33 @@ impl<'a> Parser<'a> {
Ok((Ident::empty(), item_kind))
}
fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> {
let span = self.token.span;
self.expect_keyword(kw::Reuse)?;
let (qself, path) = if self.eat_lt() {
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
(Some(qself), path)
} else {
(None, self.parse_path(PathStyle::Expr)?)
};
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
Some(self.parse_block()?)
} else {
self.expect(&token::Semi)?;
None
};
let span = span.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::fn_delegation, span);
let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty());
Ok((
ident,
ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })),
))
}
fn parse_item_list<T>(
&mut self,
attrs: &mut AttrVec,

View file

@ -1170,7 +1170,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
sym::rust_logo => {
if !self.tcx.features().rustdoc_internals {
feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::rustdoc_internals,
meta.span(),
"the `#[doc(rust_logo)]` attribute is used for Rust branding",
@ -1815,7 +1815,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
(target, self.tcx.features().fn_align)
{
feature_err(
&self.tcx.sess.parse_sess,
&self.tcx.sess,
sym::fn_align,
hint.span(),
"`repr(align)` attributes on functions are unstable",

View file

@ -147,7 +147,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
[missing_primary, ref missing_secondary @ ..] => {
let msg =
format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, msg);
let mut err = feature_err(&tcx.sess, *missing_primary, span, msg);
// If multiple feature gates would be required to enable this expression, include
// them as help messages. Don't emit a separate error for each missing feature gate.

View file

@ -45,14 +45,13 @@ impl DebuggerVisualizerCollector<'_> {
}
};
let file =
match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) {
Ok(file) => file,
Err(err) => {
err.emit();
return;
}
};
let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
Ok(file) => file,
Err(err) => {
err.emit();
return;
}
};
match std::fs::read(&file) {
Ok(contents) => {

View file

@ -135,7 +135,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
if main_def.is_import && !tcx.features().imported_main {
let span = main_def.span;
feature_err(
&tcx.sess.parse_sess,
&tcx.sess,
sym::imported_main,
span,
"using an imported function as entry point `main` is experimental",

View file

@ -341,6 +341,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
record_variants!(
(self, t, t.kind, Id::Node(t.hir_id), hir, Ty, TyKind),
[
InferDelegation,
Slice,
Array,
Ptr,
@ -521,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
TraitAlias,
Impl,
MacCall,
MacroDef
MacroDef,
Delegation
]
);
ast_visit::walk_item(self, i)
@ -645,7 +647,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
record_variants!(
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
[Const, Fn, Type, MacCall]
[Const, Fn, Type, MacCall, Delegation]
);
ast_visit::walk_assoc_item(self, i, ctxt);
}

View file

@ -271,7 +271,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
ast::ItemKind::Use(_) => Target::Use,
ast::ItemKind::Static(_) => Target::Static,
ast::ItemKind::Const(_) => Target::Const,
ast::ItemKind::Fn(_) => Target::Fn,
ast::ItemKind::Fn(_) | ast::ItemKind::Delegation(..) => Target::Fn,
ast::ItemKind::Mod(_, _) => Target::Mod,
ast::ItemKind::ForeignMod(_) => Target::ForeignFn,
ast::ItemKind::GlobalAsm(_) => Target::GlobalAsm,
@ -315,24 +315,29 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) {
let (target, generics) = match &i.kind {
ast::AssocItemKind::Fn(fun) => (
match &self.parent_item.unwrap().kind {
ast::ItemKind::Impl(i) => {
if i.of_trait.is_some() {
Target::Method(MethodKind::Trait { body: fun.body.is_some() })
} else {
Target::Method(MethodKind::Inherent)
ast::AssocItemKind::Fn(..) | ast::AssocItemKind::Delegation(..) => {
let (body, generics) = if let ast::AssocItemKind::Fn(fun) = &i.kind {
(fun.body.is_some(), Some(&fun.generics))
} else {
(true, None)
};
(
match &self.parent_item.unwrap().kind {
ast::ItemKind::Impl(i) => {
if i.of_trait.is_some() {
Target::Method(MethodKind::Trait { body })
} else {
Target::Method(MethodKind::Inherent)
}
}
}
ast::ItemKind::Trait(_) => {
Target::Method(MethodKind::Trait { body: fun.body.is_some() })
}
_ => unreachable!(),
},
&fun.generics,
),
ast::AssocItemKind::Const(ct) => (Target::AssocConst, &ct.generics),
ast::AssocItemKind::Type(ty) => (Target::AssocTy, &ty.generics),
ast::ItemKind::Trait(_) => Target::Method(MethodKind::Trait { body }),
_ => unreachable!(),
},
generics,
)
}
ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
};
@ -341,7 +346,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
self.resolver.node_id_to_def_id[&i.id],
&i.attrs,
i.span,
Some(generics),
generics,
);
visit::walk_assoc_item(self, i, ctxt);

View file

@ -16,7 +16,7 @@ use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_code_err, Applicability};
@ -686,10 +686,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
// These items live in the value namespace.
ItemKind::Static(..) => {
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
}
ItemKind::Const(..) => {
ItemKind::Const(..) | ItemKind::Delegation(..) | ItemKind::Static(..) => {
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
}
ItemKind::Fn(..) => {
@ -701,11 +698,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
// These items live in the type namespace.
ItemKind::TyAlias(..) => {
ItemKind::TyAlias(..) | ItemKind::TraitAlias(..) => {
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
ItemKind::Enum(_, _) => {
ItemKind::Enum(_, _) | ItemKind::Trait(..) => {
let module = self.r.new_module(
Some(parent),
ModuleKind::Def(def_kind, def_id, ident.name),
@ -717,10 +714,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.parent_scope.module = module;
}
ItemKind::TraitAlias(..) => {
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
// These items live in both the type and value namespaces.
ItemKind::Struct(ref vdata, _) => {
// Define a name in the type namespace.
@ -778,19 +771,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.insert_field_visibilities_local(def_id, vdata);
}
ItemKind::Trait(..) => {
// Add all the items within to a new module.
let module = self.r.new_module(
Some(parent),
ModuleKind::Def(def_kind, def_id, ident.name),
expansion.to_expn_id(),
item.span,
parent.no_implicit_prelude,
);
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.parent_scope.module = module;
}
// These items do not add names to modules.
ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => {
self.r.trait_impl_items.insert(local_def_id);
@ -1358,13 +1338,9 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
if ctxt == AssocCtxt::Trait {
let ns = match item.kind {
AssocItemKind::Const(..) => ValueNS,
AssocItemKind::Fn(box Fn { ref sig, .. }) => {
if sig.decl.has_self() {
self.r.has_self.insert(local_def_id);
}
ValueNS
}
AssocItemKind::Const(..)
| AssocItemKind::Delegation(..)
| AssocItemKind::Fn(..) => ValueNS,
AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) => bug!(), // handled above
};

View file

@ -111,7 +111,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ItemKind::TyAlias(..) => DefKind::TyAlias,
ItemKind::Static(s) => DefKind::Static(s.mutability),
ItemKind::Const(..) => DefKind::Const,
ItemKind::Fn(..) => DefKind::Fn,
ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
ItemKind::MacroDef(..) => {
let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition());
let macro_kind = macro_data.ext.macro_kind();
@ -259,7 +259,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
let def_kind = match &i.kind {
AssocItemKind::Fn(..) => DefKind::AssocFn,
AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn,
AssocItemKind::Const(..) => DefKind::AssocConst,
AssocItemKind::Type(..) => DefKind::AssocTy,
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),

View file

@ -786,7 +786,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
}
ResolutionError::FailedToResolve { last_segment, label, suggestion, module } => {
ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
let mut err =
struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {}", &label);
err.span_label(span, label);
@ -801,9 +801,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some(ModuleOrUniformRoot::Module(module)) = module
&& let Some(module) = module.opt_def_id()
&& let Some(last_segment) = last_segment
&& let Some(segment) = segment
{
self.find_cfg_stripped(&mut err, &last_segment, module);
self.find_cfg_stripped(&mut err, &segment, module);
}
err
@ -981,12 +981,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
span,
ResolutionError::FailedToResolve {
last_segment: None,
label,
suggestion,
module: None,
},
ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
),
VisResolutionError::ExpectedFound(span, path_str, res) => {
self.dcx().create_err(errs::ExpectedFound { span, res, path_str })
@ -2450,7 +2445,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub(crate) fn find_cfg_stripped(
&mut self,
err: &mut Diagnostic,
last_segment: &Symbol,
segment: &Symbol,
module: DefId,
) {
let local_items;
@ -2469,7 +2464,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
};
for &StrippedCfgItem { parent_module, name, ref cfg } in symbols {
if parent_module != module || name.name != *last_segment {
if parent_module != module || name.name != *segment {
continue;
}

View file

@ -277,7 +277,8 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't
| ast::ItemKind::TraitAlias(..)
| ast::ItemKind::MacroDef(..)
| ast::ItemKind::ForeignMod(..)
| ast::ItemKind::Fn(..) => return,
| ast::ItemKind::Fn(..)
| ast::ItemKind::Delegation(..) => return,
}
}
}

View file

@ -1381,13 +1381,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
continue;
}
}
return PathResult::failed(
ident.span,
false,
finalize.is_some(),
module,
|| ("there are too many leading `super` keywords".to_string(), None),
);
return PathResult::failed(ident, false, finalize.is_some(), module, || {
("there are too many leading `super` keywords".to_string(), None)
});
}
if segment_idx == 0 {
if name == kw::SelfLower {
@ -1419,7 +1415,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Report special messages for path segment keywords in wrong positions.
if ident.is_path_segment_keyword() && segment_idx != 0 {
return PathResult::failed(ident.span, false, finalize.is_some(), module, || {
return PathResult::failed(ident, false, finalize.is_some(), module, || {
let name_str = if name == kw::PathRoot {
"crate root".to_string()
} else {
@ -1515,7 +1511,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
));
} else {
return PathResult::failed(
ident.span,
ident,
is_last,
finalize.is_some(),
module,
@ -1541,24 +1537,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
return PathResult::failed(
ident.span,
is_last,
finalize.is_some(),
module,
|| {
self.report_path_resolution_error(
path,
opt_ns,
parent_scope,
ribs,
ignore_binding,
module,
segment_idx,
ident,
)
},
);
return PathResult::failed(ident, is_last, finalize.is_some(), module, || {
self.report_path_resolution_error(
path,
opt_ns,
parent_scope,
ribs,
ignore_binding,
module,
segment_idx,
ident,
)
});
}
}
}

View file

@ -886,6 +886,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PathResult::Failed {
is_error_from_last_segment: false,
span,
segment_name,
label,
suggestion,
module,
@ -895,7 +896,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.report_error(
span,
ResolutionError::FailedToResolve {
last_segment: None,
segment: Some(segment_name),
label,
suggestion,
module,

View file

@ -394,13 +394,18 @@ pub(crate) enum PathSource<'a> {
TupleStruct(Span, &'a [Span]),
// `m::A::B` in `<T as m::A>::B::C`.
TraitItem(Namespace),
// Paths in delegation item
Delegation,
}
impl<'a> PathSource<'a> {
fn namespace(self) -> Namespace {
match self {
PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) => ValueNS,
PathSource::Expr(..)
| PathSource::Pat
| PathSource::TupleStruct(..)
| PathSource::Delegation => ValueNS,
PathSource::TraitItem(ns) => ns,
}
}
@ -412,7 +417,7 @@ impl<'a> PathSource<'a> {
| PathSource::Pat
| PathSource::Struct
| PathSource::TupleStruct(..) => true,
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Delegation => false,
}
}
@ -454,6 +459,7 @@ impl<'a> PathSource<'a> {
},
_ => "value",
},
PathSource::Delegation => "function",
}
}
@ -521,6 +527,7 @@ impl<'a> PathSource<'a> {
Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
_ => false,
},
PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
}
}
@ -533,8 +540,8 @@ impl<'a> PathSource<'a> {
(PathSource::Type, false) => error_code!(E0412),
(PathSource::Struct, true) => error_code!(E0574),
(PathSource::Struct, false) => error_code!(E0422),
(PathSource::Expr(..), true) => error_code!(E0423),
(PathSource::Expr(..), false) => error_code!(E0425),
(PathSource::Expr(..), true) | (PathSource::Delegation, true) => error_code!(E0423),
(PathSource::Expr(..), false) | (PathSource::Delegation, false) => error_code!(E0425),
(PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532),
(PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531),
(PathSource::TraitItem(..), true) => error_code!(E0575),
@ -1805,7 +1812,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
PathSource::Expr(..)
| PathSource::Pat
| PathSource::Struct
| PathSource::TupleStruct(..) => true,
| PathSource::TupleStruct(..)
| PathSource::Delegation => true,
};
if inferred {
// Do not create a parameter for patterns and expressions: type checking can infer
@ -2514,6 +2522,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
visit::walk_item(self, item);
}
ItemKind::Delegation(ref delegation) => {
self.resolve_delegation(delegation);
}
ItemKind::ExternCrate(..) => {}
ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"),
@ -2790,6 +2802,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
}
AssocItemKind::Delegation(delegation) => {
self.resolve_delegation(delegation);
}
AssocItemKind::Type(box TyAlias { generics, .. }) => self
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
@ -3036,6 +3051,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
},
);
}
AssocItemKind::Delegation(box delegation) => {
debug!("resolve_implementation AssocItemKind::Delegation");
self.check_trait_item(
item.id,
item.ident,
&item.kind,
ValueNS,
item.span,
seen_trait_items,
|i, s, c| MethodNotMemberOfTrait(i, s, c),
);
self.resolve_delegation(delegation);
}
AssocItemKind::MacCall(_) => {
panic!("unexpanded macro in resolve!")
}
@ -3123,7 +3151,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
match (def_kind, kind) {
(DefKind::AssocTy, AssocItemKind::Type(..))
| (DefKind::AssocFn, AssocItemKind::Fn(..))
| (DefKind::AssocConst, AssocItemKind::Const(..)) => {
| (DefKind::AssocConst, AssocItemKind::Const(..))
| (DefKind::AssocFn, AssocItemKind::Delegation(..)) => {
self.r.record_partial_res(id, PartialRes::new(res));
return;
}
@ -3136,6 +3165,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"),
AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"),
AssocItemKind::Type(..) => (rustc_errors::error_code!(E0325), "type"),
AssocItemKind::Delegation(..) => (rustc_errors::error_code!(E0324), "method"),
AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
};
let trait_path = path_names_to_string(path);
@ -3159,6 +3189,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
})
}
fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
self.smart_resolve_path(
delegation.id,
&delegation.qself,
&delegation.path,
PathSource::Delegation,
);
if let Some(qself) = &delegation.qself {
self.visit_ty(&qself.ty);
}
self.visit_path(&delegation.path, delegation.id);
if let Some(body) = &delegation.body {
// `PatBoundCtx` is not necessary in this context
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
let span = delegation.path.segments.last().unwrap().ident.span;
self.fresh_binding(
Ident::new(kw::SelfLower, span),
delegation.id,
PatternSource::FnParam,
&mut bindings,
);
self.visit_block(body);
}
}
fn resolve_params(&mut self, params: &'ast [Param]) {
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
@ -3998,11 +4054,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
label,
suggestion,
module,
segment_name,
} => {
return Err(respan(
span,
ResolutionError::FailedToResolve {
last_segment: None,
segment: Some(segment_name),
label,
suggestion,
module,
@ -4551,13 +4608,24 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
}
struct LifetimeCountVisitor<'a, 'b, 'tcx> {
/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
/// lifetime generic parameters and function parameters.
struct ItemInfoCollector<'a, 'b, 'tcx> {
r: &'b mut Resolver<'a, 'tcx>,
}
/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
/// lifetime generic parameters.
impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
impl ItemInfoCollector<'_, '_, '_> {
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) {
let def_id = self.r.local_def_id(id);
self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len());
if sig.decl.has_self() {
self.r.has_self.insert(def_id);
}
}
}
impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
fn visit_item(&mut self, item: &'ast Item) {
match &item.kind {
ItemKind::TyAlias(box TyAlias { ref generics, .. })
@ -4569,6 +4637,10 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
| ItemKind::Impl(box Impl { ref generics, .. })
| ItemKind::Trait(box Trait { ref generics, .. })
| ItemKind::TraitAlias(ref generics, _) => {
if let ItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
self.collect_fn_info(sig, item.id);
}
let def_id = self.r.local_def_id(item.id);
let count = generics
.params
@ -4586,14 +4658,27 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
| ItemKind::MacroDef(..)
| ItemKind::GlobalAsm(..)
| ItemKind::MacCall(..) => {}
ItemKind::Delegation(..) => {
// Delegated functions have lifetimes, their count is not necessarily zero.
// But skipping the delegation items here doesn't mean that the count will be considered zero,
// it means there will be a panic when retrieving the count,
// but for delegation items we are never actually retrieving that count in practice.
}
}
visit::walk_item(self, item)
}
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
if let AssocItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
self.collect_fn_info(sig, item.id);
}
visit::walk_assoc_item(self, item, ctxt);
}
}
impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
visit::walk_crate(&mut ItemInfoCollector { r: self }, krate);
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID));
visit::walk_crate(&mut late_resolution_visitor, krate);

View file

@ -656,7 +656,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let typo_sugg = self
.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
.to_opt_suggestion();
if path.len() == 1 && self.self_type_is_available() {
if path.len() == 1
&& !matches!(source, PathSource::Delegation)
&& self.self_type_is_available()
{
if let Some(candidate) =
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
{
@ -1899,6 +1902,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
(AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
(AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
(AssocItemKind::Type(..), Res::Def(DefKind::AssocTy, _)) => true,
(AssocItemKind::Delegation(_), Res::Def(DefKind::AssocFn, _)) => true,
_ => false,
})
.map(|(key, _)| key.ident.name)
@ -1960,6 +1964,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
ast::AssocItemKind::Delegation(..)
if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) =>
{
AssocSuggestion::MethodWithSelf { called }
}
ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::MacCall(_) => continue,
});
}

View file

@ -213,7 +213,7 @@ enum ResolutionError<'a> {
SelfImportOnlyInImportListWithNonEmptyPrefix,
/// Error E0433: failed to resolve.
FailedToResolve {
last_segment: Option<Symbol>,
segment: Option<Symbol>,
label: String,
suggestion: Option<Suggestion>,
module: Option<ModuleOrUniformRoot<'a>>,
@ -396,12 +396,14 @@ enum PathResult<'a> {
suggestion: Option<Suggestion>,
is_error_from_last_segment: bool,
module: Option<ModuleOrUniformRoot<'a>>,
/// The segment name of target
segment_name: Symbol,
},
}
impl<'a> PathResult<'a> {
fn failed(
span: Span,
ident: Ident,
is_error_from_last_segment: bool,
finalize: bool,
module: Option<ModuleOrUniformRoot<'a>>,
@ -409,7 +411,14 @@ impl<'a> PathResult<'a> {
) -> PathResult<'a> {
let (label, suggestion) =
if finalize { label_and_suggestion() } else { (String::new(), None) };
PathResult::Failed { span, label, suggestion, is_error_from_last_segment, module }
PathResult::Failed {
span: ident.span,
segment_name: ident.name,
label,
suggestion,
is_error_from_last_segment,
module,
}
}
}
@ -1101,6 +1110,8 @@ pub struct Resolver<'a, 'tcx> {
legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
/// Amount of lifetime parameters for each item in the crate.
item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
/// Amount of parameters for each function in the crate.
fn_parameter_counts: LocalDefIdMap<usize>,
main_def: Option<MainDefinition>,
trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
@ -1439,6 +1450,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
doc_link_resolutions: Default::default(),
doc_link_traits_in_scope: Default::default(),
all_macro_rules: Default::default(),
fn_parameter_counts: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@ -1542,6 +1554,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
trait_map: self.trait_map,
lifetime_elision_allowed: self.lifetime_elision_allowed,
lint_buffer: Steal::new(self.lint_buffer),
has_self: self.has_self,
fn_parameter_counts: self.fn_parameter_counts,
};
ResolverOutputs { global_ctxt, ast_lowering }
}

View file

@ -594,13 +594,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if soft_custom_inner_attributes_gate {
self.tcx.sess.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
} else {
feature_err(
&self.tcx.sess.parse_sess,
sym::custom_inner_attributes,
path.span,
msg,
)
.emit();
feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
}
}
@ -779,7 +773,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.report_error(
span,
ResolutionError::FailedToResolve {
last_segment: path.last().map(|segment| segment.ident.name),
segment: path.last().map(|segment| segment.ident.name),
label,
suggestion,
module,

View file

@ -24,6 +24,9 @@ session_feature_diagnostic_for_issue =
session_feature_diagnostic_help =
add `#![feature({$feature})]` to the crate attributes to enable
session_feature_suggest_upgrade_compiler =
this compiler was built on {$date}; consider upgrading it if it is out of date
session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
session_file_write_fail = failed to write `{$path}` due to error `{$err}`

View file

@ -1,7 +1,7 @@
//! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`!
//! NOTE: Keep these constants in sync with `library/std/src/sys/pal/unix/mod.rs`!
/// The default value if `#[unix_sigpipe]` is not specified. This resolves
/// to `SIG_IGN` in `library/std/src/sys/unix/mod.rs`.
/// to `SIG_IGN` in `library/std/src/sys/pal/unix/mod.rs`.
///
/// Note that `SIG_IGN` has been the Rust default since 2014. See
/// <https://github.com/rust-lang/rust/issues/62569>.

View file

@ -1,6 +1,5 @@
use std::num::NonZeroU32;
use crate::parse::ParseSess;
use rustc_ast::token;
use rustc_ast::util::literal::LitError;
use rustc_errors::{
@ -10,6 +9,8 @@ use rustc_macros::Diagnostic;
use rustc_span::{BytePos, Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
use crate::parse::ParseSess;
pub struct FeatureGateError {
pub span: MultiSpan,
pub explain: DiagnosticMessage,
@ -30,6 +31,24 @@ pub struct FeatureDiagnosticForIssue {
pub n: NonZeroU32,
}
#[derive(Subdiagnostic)]
#[note(session_feature_suggest_upgrade_compiler)]
pub struct SuggestUpgradeCompiler {
date: &'static str,
}
impl SuggestUpgradeCompiler {
pub fn ui_testing() -> Self {
Self { date: "YYYY-MM-DD" }
}
pub fn new() -> Option<Self> {
let date = option_env!("CFG_VER_DATE")?;
Some(Self { date })
}
}
#[derive(Subdiagnostic)]
#[help(session_feature_diagnostic_help)]
pub struct FeatureDiagnosticHelp {

View file

@ -4,10 +4,12 @@
use crate::config::{Cfg, CheckCfg};
use crate::errors::{
CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError,
SuggestUpgradeCompiler,
};
use crate::lint::{
builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
};
use crate::Session;
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc};
@ -75,11 +77,12 @@ impl SymbolGallery {
}
}
// todo: this function now accepts `Session` instead of `ParseSess` and should be relocated
/// Construct a diagnostic for a language feature error due to the given `span`.
/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbols`.
#[track_caller]
pub fn feature_err(
sess: &ParseSess,
sess: &Session,
feature: Symbol,
span: impl Into<MultiSpan>,
explain: impl Into<DiagnosticMessage>,
@ -93,7 +96,7 @@ pub fn feature_err(
/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
#[track_caller]
pub fn feature_err_issue(
sess: &ParseSess,
sess: &Session,
feature: Symbol,
span: impl Into<MultiSpan>,
issue: GateIssue,
@ -103,12 +106,14 @@ pub fn feature_err_issue(
// Cancel an earlier warning for this same error, if it exists.
if let Some(span) = span.primary_span() {
if let Some(err) = sess.dcx.steal_diagnostic(span, StashKey::EarlySyntaxWarning) {
if let Some(err) = sess.parse_sess.dcx.steal_diagnostic(span, StashKey::EarlySyntaxWarning)
{
err.cancel()
}
}
let mut err = sess.dcx.create_err(FeatureGateError { span, explain: explain.into() });
let mut err =
sess.parse_sess.dcx.create_err(FeatureGateError { span, explain: explain.into() });
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false);
err
}
@ -117,7 +122,7 @@ pub fn feature_err_issue(
///
/// This diagnostic is only a warning and *does not cause compilation to fail*.
#[track_caller]
pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &'static str) {
pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) {
feature_warn_issue(sess, feature, span, GateIssue::Language, explain);
}
@ -131,13 +136,13 @@ pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &'st
#[allow(rustc::untranslatable_diagnostic)]
#[track_caller]
pub fn feature_warn_issue(
sess: &ParseSess,
sess: &Session,
feature: Symbol,
span: Span,
issue: GateIssue,
explain: &'static str,
) {
let mut err = sess.dcx.struct_span_warn(span, explain);
let mut err = sess.parse_sess.dcx.struct_span_warn(span, explain);
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false);
// Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
@ -152,7 +157,7 @@ pub fn feature_warn_issue(
}
/// Adds the diagnostics for a feature to an existing error.
pub fn add_feature_diagnostics(err: &mut Diagnostic, sess: &ParseSess, feature: Symbol) {
pub fn add_feature_diagnostics(err: &mut Diagnostic, sess: &Session, feature: Symbol) {
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false);
}
@ -163,7 +168,7 @@ pub fn add_feature_diagnostics(err: &mut Diagnostic, sess: &ParseSess, feature:
/// `add_feature_diagnostics`.
pub fn add_feature_diagnostics_for_issue(
err: &mut Diagnostic,
sess: &ParseSess,
sess: &Session,
feature: Symbol,
issue: GateIssue,
feature_from_cli: bool,
@ -173,12 +178,18 @@ pub fn add_feature_diagnostics_for_issue(
}
// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
if sess.unstable_features.is_nightly_build() {
if sess.parse_sess.unstable_features.is_nightly_build() {
if feature_from_cli {
err.subdiagnostic(CliFeatureDiagnosticHelp { feature });
} else {
err.subdiagnostic(FeatureDiagnosticHelp { feature });
}
if sess.opts.unstable_opts.ui_testing {
err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
} else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
err.subdiagnostic(suggestion);
}
}
}

View file

@ -318,7 +318,7 @@ impl Session {
if err.code.is_none() {
err.code(error_code!(E0658));
}
add_feature_diagnostics(&mut err, &self.parse_sess, feature);
add_feature_diagnostics(&mut err, self, feature);
err
}

View file

@ -102,6 +102,7 @@ symbols! {
Gen: "gen",
MacroRules: "macro_rules",
Raw: "raw",
Reuse: "reuse",
Union: "union",
Yeet: "yeet",
}

View file

@ -840,7 +840,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
"sparc" => sparc::compute_abi_info(cx, self),
"sparc64" => sparc64::compute_abi_info(cx, self),
"nvptx64" => {
if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::PtxKernel {
nvptx64::compute_ptx_kernel_abi_info(cx, self)
} else {
nvptx64::compute_abi_info(self)
@ -849,7 +849,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
"hexagon" => hexagon::compute_abi_info(self),
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
"wasm32" | "wasm64" => {
if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::Wasm {
if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::Wasm {
wasm::compute_wasm_abi_info(self)
} else {
wasm::compute_c_abi_info(cx, self)

View file

@ -70,15 +70,16 @@ impl Abi {
// * C and Cdecl obviously support varargs.
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
// * EfiApi is based on Win64 or C, so it also supports it.
// * System falls back to C for functions with varargs.
//
// * Stdcall does not, because it would be impossible for the callee to clean
// up the arguments. (callee doesn't know how many arguments are there)
// * Same for Fastcall, Vectorcall and Thiscall.
// * System can become Stdcall, so is also a no-no.
// * Other calling conventions are related to hardware or the compiler itself.
match self {
Self::C { .. }
| Self::Cdecl { .. }
| Self::System { .. }
| Self::Aapcs { .. }
| Self::Win64 { .. }
| Self::SysV64 { .. }

View file

@ -39,7 +39,7 @@ pub fn opts() -> TargetOptions {
// While we support ELF TLS, rust requires a way to register
// cleanup handlers (in C, this would be something along the lines of:
// void register_callback(void (*fn)(void *), void *arg);
// (see src/libstd/sys/unix/fast_thread_local.rs) that is currently
// (see src/libstd/sys/pal/unix/fast_thread_local.rs) that is currently
// missing in illumos. For now at least, we must fallback to using
// pthread_{get,set}specific.
//has_thread_local: true,

View file

@ -2401,10 +2401,14 @@ impl DerefMut for Target {
impl Target {
/// Given a function ABI, turn it into the correct ABI for this target.
pub fn adjust_abi(&self, abi: Abi) -> Abi {
pub fn adjust_abi(&self, abi: Abi, c_variadic: bool) -> Abi {
match abi {
Abi::C { .. } => self.default_adjusted_cabi.unwrap_or(abi),
Abi::System { unwind } if self.is_like_windows && self.arch == "x86" => {
// On Windows, `extern "system"` behaves like msvc's `__stdcall`.
// `__stdcall` only applies on x86 and on non-variadic functions:
// https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
Abi::System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => {
Abi::Stdcall { unwind }
}
Abi::System { unwind } => Abi::C { unwind },

View file

@ -408,7 +408,7 @@ impl<'tcx> OnUnimplementedDirective {
.ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
.meta_item()
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
if let Some(value) = cfg.value
&& let Err(guar) = parse_value(value, cfg.span)
{
@ -682,31 +682,22 @@ impl<'tcx> OnUnimplementedDirective {
for command in self.subcommands.iter().chain(Some(self)).rev() {
if let Some(ref condition) = command.condition
&& !attr::eval_condition(
condition,
&tcx.sess.parse_sess,
Some(tcx.features()),
&mut |cfg| {
let value = cfg.value.map(|v| {
// `with_no_visible_paths` is also used when generating the options,
// so we need to match it here.
ty::print::with_no_visible_paths!(
OnUnimplementedFormatString {
symbol: v,
span: cfg.span,
is_diagnostic_namespace_variant: false
}
.format(
tcx,
trait_ref,
&options_map
)
)
});
&& !attr::eval_condition(condition, &tcx.sess, Some(tcx.features()), &mut |cfg| {
let value = cfg.value.map(|v| {
// `with_no_visible_paths` is also used when generating the options,
// so we need to match it here.
ty::print::with_no_visible_paths!(
OnUnimplementedFormatString {
symbol: v,
span: cfg.span,
is_diagnostic_namespace_variant: false
}
.format(tcx, trait_ref, &options_map)
)
});
options.contains(&(cfg.name, value))
},
)
options.contains(&(cfg.name, value))
})
{
debug!("evaluate: skipping {:?} due to condition", command);
continue;

View file

@ -947,9 +947,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Overflow(_) => {
bug!("overflow should be handled before the `report_selection_error` path");
}
SelectionError::ErrorReporting => {
bug!("ErrorReporting Overflow should not reach `report_selection_err` call")
}
};
self.note_obligation_cause(&mut err, &obligation);
@ -3459,14 +3456,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
if !self.reported_signature_mismatch.borrow_mut().insert((span, found_span)) {
// We check closures twice, with obligations flowing in different directions,
// but we want to complain about them only once.
return None;
}
self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
let mut not_tupled = false;
let found = match found_trait_ref.skip_binder().args.type_at(1).kind() {

View file

@ -116,11 +116,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
r,
)
}
OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr,
OverflowError::Error(_) => EvaluationResult::EvaluatedToErr,
})
}
Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr,
Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr,
}
}

View file

@ -14,9 +14,9 @@ use super::util;
use super::util::closure_trait_ref_and_return_type;
use super::wf;
use super::{
ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
ObligationCause, ObligationCauseCode, Overflow, PolyTraitObligation, PredicateObligation,
Selection, SelectionError, SelectionResult, TraitQueryMode,
ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, ObligationCause,
ObligationCauseCode, Overflow, PolyTraitObligation, PredicateObligation, Selection,
SelectionError, SelectionResult, TraitQueryMode,
};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
@ -496,7 +496,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
Ok(_) => Ok(None),
Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
})
.flat_map(Result::transpose)
@ -1233,7 +1232,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
Err(..) => Ok(EvaluatedToErr),
}
}

View file

@ -228,9 +228,9 @@ fn fn_sig_for_fn_abi<'tcx>(
}
#[inline]
fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv {
use rustc_target::spec::abi::Abi::*;
match tcx.sess.target.adjust_abi(abi) {
match tcx.sess.target.adjust_abi(abi, c_variadic) {
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
// This is intentionally not using `Conv::Cold`, as that has to preserve
@ -488,7 +488,7 @@ fn fn_abi_new_uncached<'tcx>(
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
let sig = cx.tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
let mut inputs = sig.inputs();
let extra_args = if sig.abi == RustCall {

View file

@ -1605,9 +1605,9 @@ mod prim_ref {}
/// type in the function pointer to the type at the function declaration, and the return value is
/// [`transmute`d][mem::transmute] from the type in the declaration to the type in the
/// pointer. All the usual caveats and concerns around transmutation apply; for instance, if the
/// function expects a `NonNullI32` and the function pointer uses the ABI-compatible type
/// `Option<NonNullI32>`, and the value used for the argument is `None`, then this call is Undefined
/// Behavior since transmuting `None::<NonNullI32>` to `NonNullI32` violates the non-null
/// function expects a `NonZeroI32` and the function pointer uses the ABI-compatible type
/// `Option<NonZeroI32>`, and the value used for the argument is `None`, then this call is Undefined
/// Behavior since transmuting `None::<NonZeroI32>` to `NonZeroI32` violates the non-zero
/// requirement.
///
/// #### Requirements concerning target features

View file

@ -329,12 +329,14 @@ impl Waker {
Waker { waker }
}
/// Creates a new `Waker` that does nothing when `wake` is called.
/// Returns a reference to a `Waker` that does nothing when used.
///
/// This is mostly useful for writing tests that need a [`Context`] to poll
/// some futures, but are not expecting those futures to wake the waker or
/// do not need to do anything specific if it happens.
///
/// If an owned `Waker` is needed, `clone()` this one.
///
/// # Examples
///
/// ```
@ -343,8 +345,7 @@ impl Waker {
/// use std::future::Future;
/// use std::task;
///
/// let waker = task::Waker::noop();
/// let mut cx = task::Context::from_waker(&waker);
/// let mut cx = task::Context::from_waker(task::Waker::noop());
///
/// let mut future = Box::pin(async { 10 });
/// assert_eq!(future.as_mut().poll(&mut cx), task::Poll::Ready(10));
@ -352,7 +353,12 @@ impl Waker {
#[inline]
#[must_use]
#[unstable(feature = "noop_waker", issue = "98286")]
pub const fn noop() -> Waker {
pub const fn noop() -> &'static Waker {
// Ideally all this data would be explicitly `static` because it is used by reference and
// only ever needs one copy. But `const fn`s (and `const` items) cannot refer to statics,
// even though their values can be promoted to static. (That might change; see #119618.)
// An alternative would be a `pub static NOOP: &Waker`, but associated static items are not
// currently allowed either, and making it non-associated would be unergonomic.
const VTABLE: RawWakerVTable = RawWakerVTable::new(
// Cloning just returns a new no-op raw waker
|_| RAW,
@ -364,8 +370,9 @@ impl Waker {
|_| {},
);
const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE);
const WAKER_REF: &Waker = &Waker { waker: RAW };
Waker { waker: RAW }
WAKER_REF
}
/// Get a reference to the underlying [`RawWaker`].

View file

@ -1,124 +1,10 @@
//! Platform-dependent platform abstraction.
//!
//! The `std::sys` module is the abstracted interface through which
//! `std` talks to the underlying operating system. It has different
//! implementations for different operating system families, today
//! just Unix and Windows, and initial support for Redox.
//!
//! The centralization of platform-specific code in this module is
//! enforced by the "platform abstraction layer" tidy script in
//! `tools/tidy/src/pal.rs`.
//!
//! This module is closely related to the platform-independent system
//! integration code in `std::sys_common`. See that module's
//! documentation for details.
//!
//! In the future it would be desirable for the independent
//! implementations of this module to be extracted to their own crates
//! that `std` can link to, thus enabling their implementation
//! out-of-tree via crate replacement. Though due to the complex
//! inter-dependencies within `std` that will be a challenging goal to
//! achieve.
/// The PAL (platform abstraction layer) contains platform-specific abstractions
/// for implementing the features in the other submodules, e.g. UNIX file
/// descriptors.
mod pal;
#![allow(missing_debug_implementations)]
pub mod common;
mod personality;
cfg_if::cfg_if! {
if #[cfg(unix)] {
mod unix;
pub use self::unix::*;
} else if #[cfg(windows)] {
mod windows;
pub use self::windows::*;
} else if #[cfg(target_os = "solid_asp3")] {
mod solid;
pub use self::solid::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use self::hermit::*;
} else if #[cfg(target_os = "wasi")] {
mod wasi;
pub use self::wasi::*;
} else if #[cfg(target_family = "wasm")] {
mod wasm;
pub use self::wasm::*;
} else if #[cfg(target_os = "xous")] {
mod xous;
pub use self::xous::*;
} else if #[cfg(target_os = "uefi")] {
mod uefi;
pub use self::uefi::*;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use self::sgx::*;
} else if #[cfg(target_os = "teeos")] {
mod teeos;
pub use self::teeos::*;
} else {
mod unsupported;
pub use self::unsupported::*;
}
}
cfg_if::cfg_if! {
// Fuchsia components default to full backtrace.
if #[cfg(target_os = "fuchsia")] {
pub const FULL_BACKTRACE_DEFAULT: bool = true;
} else {
pub const FULL_BACKTRACE_DEFAULT: bool = false;
}
}
#[cfg(not(test))]
cfg_if::cfg_if! {
if #[cfg(target_os = "android")] {
pub use self::android::log2f32;
pub use self::android::log2f64;
} else {
#[inline]
pub fn log2f32(n: f32) -> f32 {
unsafe { crate::intrinsics::log2f32(n) }
}
#[inline]
pub fn log2f64(n: f64) -> f64 {
unsafe { crate::intrinsics::log2f64(n) }
}
}
}
// Solaris/Illumos requires a wrapper around log, log2, and log10 functions
// because of their non-standard behavior (e.g., log(-n) returns -Inf instead
// of expected NaN).
#[cfg(not(test))]
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
#[inline]
pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
if n.is_finite() {
if n > 0.0 {
log_fn(n)
} else if n == 0.0 {
f64::NEG_INFINITY // log(0) = -Inf
} else {
f64::NAN // log(-n) = NaN
}
} else if n.is_nan() {
n // log(NaN) = NaN
} else if n > 0.0 {
n // log(Inf) = Inf
} else {
f64::NAN // log(-Inf) = NaN
}
}
#[cfg(not(test))]
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
#[inline]
pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
log_fn(n)
}
#[cfg(not(target_os = "uefi"))]
pub type RawOsError = i32;
// FIXME(117276): remove this, move feature implementations into individual
// submodules.
pub use pal::*;

Some files were not shown because too many files have changed in this diff Show more