mirror of
https://git.proxmox.com/git/rustc
synced 2026-01-07 01:17:23 +00:00
New upstream version 1.65.0+dfsg1
This commit is contained in:
parent
064997fbe6
commit
f2b60f7d56
869
Cargo.lock
generated
869
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
@ -33,8 +33,10 @@ members = [
|
||||
"src/tools/unicode-table-generator",
|
||||
"src/tools/expand-yaml-anchors",
|
||||
"src/tools/jsondocck",
|
||||
"src/tools/jsondoclint",
|
||||
"src/tools/html-checker",
|
||||
"src/tools/bump-stage0",
|
||||
"src/tools/replace-version-placeholder",
|
||||
"src/tools/lld-wrapper",
|
||||
]
|
||||
|
||||
@ -96,21 +98,6 @@ gimli.debug = 0
|
||||
miniz_oxide.debug = 0
|
||||
object.debug = 0
|
||||
|
||||
# We want the RLS to use the version of Cargo that we've got vendored in this
|
||||
# repository to ensure that the same exact version of Cargo is used by both the
|
||||
# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository
|
||||
# so we use a `[patch]` here to override the github repository with our local
|
||||
# vendored copy.
|
||||
[patch."https://github.com/rust-lang/cargo"]
|
||||
cargo = { path = "src/tools/cargo" }
|
||||
cargo-util = { path = "src/tools/cargo/crates/cargo-util" }
|
||||
|
||||
[patch."https://github.com/rust-lang/rustfmt"]
|
||||
# Similar to Cargo above we want the RLS to use a vendored version of `rustfmt`
|
||||
# that we're shipping as well (to ensure that the rustfmt in RLS and the
|
||||
# `rustfmt` executable are the same exact version).
|
||||
rustfmt-nightly = { path = "src/tools/rustfmt" }
|
||||
|
||||
[patch.crates-io]
|
||||
# See comments in `src/tools/rustc-workspace-hack/README.md` for what's going on
|
||||
# here
|
||||
|
||||
27
README.md
27
README.md
@ -22,7 +22,7 @@ Read ["Installation"] from [The Book].
|
||||
## 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 in the root of the project.
|
||||
which manages the bootstrapping process. It lives at the root of the project.
|
||||
|
||||
The `x.py` command can be run directly on most systems in the following format:
|
||||
|
||||
@ -32,7 +32,7 @@ The `x.py` command can be run directly on most systems in the following format:
|
||||
|
||||
This is how the documentation and examples assume you are running `x.py`.
|
||||
|
||||
Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself:
|
||||
Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case, you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself:
|
||||
|
||||
```sh
|
||||
# Python 3
|
||||
@ -83,7 +83,7 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide
|
||||
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.
|
||||
|
||||
Create install directory if you are not installing in default directory.
|
||||
Create an install directory if you are not installing in the default directory.
|
||||
|
||||
4. Build and install:
|
||||
|
||||
@ -103,11 +103,10 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide
|
||||
### Building on Windows
|
||||
|
||||
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:
|
||||
for interop with software produced by Visual Studio use the MSVC build of Rust;
|
||||
for interop with GNU software built using the MinGW/MSYS2 toolchain use the GNU
|
||||
build.
|
||||
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
|
||||
|
||||
@ -115,10 +114,10 @@ build.
|
||||
|
||||
[msys2]: https://www.msys2.org/
|
||||
|
||||
1. Grab the latest [MSYS2 installer][msys2] and go through the installer.
|
||||
1. Download the latest [MSYS2 installer][msys2] and go through the installer.
|
||||
|
||||
2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed
|
||||
MSYS2 (i.e. `C:\msys64`), depending on whether you want 32-bit or 64-bit
|
||||
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)
|
||||
|
||||
@ -153,7 +152,7 @@ build.
|
||||
#### 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 the
|
||||
(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/
|
||||
@ -168,7 +167,7 @@ shell with:
|
||||
python x.py build
|
||||
```
|
||||
|
||||
Currently, building Rust only works with some known versions of Visual Studio. If
|
||||
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.
|
||||
@ -225,7 +224,7 @@ the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will
|
||||
|
||||
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 a connection to the Internet, to
|
||||
development). As such, source builds require an Internet connection to
|
||||
fetch snapshots, and an OS that can execute the available snapshot binaries.
|
||||
|
||||
Snapshot binaries are currently built and tested on several platforms:
|
||||
|
||||
103
RELEASES.md
103
RELEASES.md
@ -1,3 +1,106 @@
|
||||
Version 1.65.0 (2022-11-03)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Error on `as` casts of enums with `#[non_exhaustive]` variants](https://github.com/rust-lang/rust/pull/92744/)
|
||||
- [Stabilize `let else`](https://github.com/rust-lang/rust/pull/93628/)
|
||||
- [Stabilize generic associated types (GATs)](https://github.com/rust-lang/rust/pull/96709/)
|
||||
- [Add lints `let_underscore_drop`, `let_underscore_lock`, and `let_underscore_must_use` from Clippy](https://github.com/rust-lang/rust/pull/97739/)
|
||||
- [Stabilize `break`ing from arbitrary labeled blocks ("label-break-value")](https://github.com/rust-lang/rust/pull/99332/)
|
||||
- [Uninitialized integers, floats, and raw pointers are now considered immediate UB](https://github.com/rust-lang/rust/pull/98919/).
|
||||
Usage of `MaybeUninit` is the correct way to work with uninitialized memory.
|
||||
- [Stabilize raw-dylib for Windows x86_64, aarch64, and thumbv7a](https://github.com/rust-lang/rust/pull/99916/)
|
||||
- [Do not allow `Drop` impl on foreign ADTs](https://github.com/rust-lang/rust/pull/99576/)
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Stabilize -Csplit-debuginfo on Linux](https://github.com/rust-lang/rust/pull/98051/)
|
||||
- [Use niche-filling optimization even when multiple variants have data](https://github.com/rust-lang/rust/pull/94075/)
|
||||
- [Associated type projections are now verified to be well-formed prior to resolving the underlying type](https://github.com/rust-lang/rust/pull/99217/#issuecomment-1209365630)
|
||||
- [Stringify non-shorthand visibility correctly](https://github.com/rust-lang/rust/pull/100350/)
|
||||
- [Normalize struct field types when unsizing](https://github.com/rust-lang/rust/pull/101831/)
|
||||
- [Update to LLVM 15](https://github.com/rust-lang/rust/pull/99464/)
|
||||
- [Fix aarch64 call abi to correctly zeroext when needed](https://github.com/rust-lang/rust/pull/97800/)
|
||||
- [debuginfo: Generalize C++-like encoding for enums](https://github.com/rust-lang/rust/pull/98393/)
|
||||
- [Add `special_module_name` lint](https://github.com/rust-lang/rust/pull/94467/)
|
||||
- [Add support for generating unique profraw files by default when using `-C instrument-coverage`](https://github.com/rust-lang/rust/pull/100384/)
|
||||
- [Allow dynamic linking for iOS/tvOS targets](https://github.com/rust-lang/rust/pull/100636/)
|
||||
|
||||
New targets:
|
||||
|
||||
- [Add armv4t-none-eabi as a tier 3 target](https://github.com/rust-lang/rust/pull/100244/)
|
||||
- [Add powerpc64-unknown-openbsd and riscv64-unknown-openbsd as tier 3 targets](https://github.com/rust-lang/rust/pull/101025/)
|
||||
- Refer to Rust's [platform support page][platform-support-doc] for more
|
||||
information on Rust's tiered platform support.
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [Don't generate `PartialEq::ne` in derive(PartialEq)](https://github.com/rust-lang/rust/pull/98655/)
|
||||
- [Windows RNG: Use `BCRYPT_RNG_ALG_HANDLE` by default](https://github.com/rust-lang/rust/pull/101325/)
|
||||
- [Forbid mixing `System` with direct system allocator calls](https://github.com/rust-lang/rust/pull/101394/)
|
||||
- [Document no support for writing to non-blocking stdio/stderr](https://github.com/rust-lang/rust/pull/101416/)
|
||||
- [`std::layout::Layout` size must not overflow `isize::MAX` when rounded up to `align`](https://github.com/rust-lang/rust/pull/95295)
|
||||
This also changes the safety conditions on `Layout::from_size_align_unchecked`.
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`std::backtrace::Backtrace`](https://doc.rust-lang.org/stable/std/backtrace/struct.Backtrace.html)
|
||||
- [`Bound::as_ref`](https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.as_ref)
|
||||
- [`std::io::read_to_string`](https://doc.rust-lang.org/stable/std/io/fn.read_to_string.html)
|
||||
- [`<*const T>::cast_mut`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_mut)
|
||||
- [`<*mut T>::cast_const`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_const)
|
||||
|
||||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`<*const T>::offset_from`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from)
|
||||
- [`<*mut T>::offset_from`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from)
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- [Apply GitHub fast path even for partial hashes](https://github.com/rust-lang/cargo/pull/10807/)
|
||||
- [Do not add home bin path to PATH if it's already there](https://github.com/rust-lang/cargo/pull/11023/)
|
||||
- [Take priority into account within the pending queue](https://github.com/rust-lang/cargo/pull/11032/).
|
||||
This slightly optimizes job scheduling by Cargo, with typically small improvements on larger crate graph builds.
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- [`std::layout::Layout` size must not overflow `isize::MAX` when rounded up to `align`](https://github.com/rust-lang/rust/pull/95295).
|
||||
This also changes the safety conditions on `Layout::from_size_align_unchecked`.
|
||||
- [`PollFn` now only implements `Unpin` if the closure is `Unpin`](https://github.com/rust-lang/rust/pull/102737).
|
||||
This is a possible breaking change if users were relying on the blanket unpin implementation.
|
||||
See discussion on the PR for details of why this change was made.
|
||||
- [Drop ExactSizeIterator impl from std::char::EscapeAscii](https://github.com/rust-lang/rust/pull/99880)
|
||||
This is a backwards-incompatible change to the standard library's surface
|
||||
area, but is unlikely to affect real world usage.
|
||||
- [Do not consider a single repeated lifetime eligible for elision in the return type](https://github.com/rust-lang/rust/pull/103450)
|
||||
This behavior was unintentionally changed in 1.64.0, and this release reverts that change by making this an error again.
|
||||
- [Reenable disabled early syntax gates as future-incompatibility lints](https://github.com/rust-lang/rust/pull/99935/)
|
||||
- [Update the minimum external LLVM to 13](https://github.com/rust-lang/rust/pull/100460/)
|
||||
- [Don't duplicate file descriptors into stdio fds](https://github.com/rust-lang/rust/pull/101426/)
|
||||
- [Sunset RLS](https://github.com/rust-lang/rust/pull/100863/)
|
||||
- [Deny usage of `#![cfg_attr(..., crate_type = ...)]` to set the crate type](https://github.com/rust-lang/rust/pull/99784/)
|
||||
This strengthens the forward compatibility lint deprecated_cfg_attr_crate_type_name to deny.
|
||||
- [`llvm-has-rust-patches` allows setting the build system to treat the LLVM as having Rust-specific patches](https://github.com/rust-lang/rust/pull/101072)
|
||||
This option may need to be set for distributions that are building Rust with a patched LLVM via `llvm-config`, not the built-in LLVM.
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Add `x.sh` and `x.ps1` shell scripts](https://github.com/rust-lang/rust/pull/99992/)
|
||||
- [compiletest: use target cfg instead of hard-coded tables](https://github.com/rust-lang/rust/pull/100260/)
|
||||
- [Use object instead of LLVM for reading bitcode from rlibs](https://github.com/rust-lang/rust/pull/98100/)
|
||||
- [Enable MIR inlining for optimized compilations](https://github.com/rust-lang/rust/pull/91743)
|
||||
This provides a 3-10% improvement in compiletimes for real world crates. See [perf results](https://perf.rust-lang.org/compare.html?start=aedf78e56b2279cc869962feac5153b6ba7001ed&end=0075bb4fad68e64b6d1be06bf2db366c30bc75e1&stat=instructions:u).
|
||||
|
||||
Version 1.64.0 (2022-09-22)
|
||||
===========================
|
||||
|
||||
|
||||
@ -33,6 +33,8 @@
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
@ -16,10 +16,12 @@
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(pointer_byte_offsets)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(ptr_const_cast)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@ -210,7 +212,7 @@ impl<T> TypedArena<T> {
|
||||
|
||||
unsafe {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
|
||||
self.ptr.set(self.ptr.get().wrapping_byte_add(1));
|
||||
let ptr = ptr::NonNull::<T>::dangling().as_ptr();
|
||||
// Don't drop the object. This `write` is equivalent to `forget`.
|
||||
ptr::write(ptr, object);
|
||||
@ -218,7 +220,7 @@ impl<T> TypedArena<T> {
|
||||
} else {
|
||||
let ptr = self.ptr.get();
|
||||
// Advance the pointer.
|
||||
self.ptr.set(self.ptr.get().offset(1));
|
||||
self.ptr.set(self.ptr.get().add(1));
|
||||
// Write into uninitialized memory.
|
||||
ptr::write(ptr, object);
|
||||
&mut *ptr
|
||||
|
||||
@ -7,12 +7,13 @@ edition = "2021"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
tracing = "0.1"
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
bitflags = "1.2.1"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
bitflags = "1.2.1"
|
||||
thin-vec = "0.2.8"
|
||||
tracing = "0.1"
|
||||
|
||||
@ -24,22 +24,19 @@ pub use UnsafeSource::*;
|
||||
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
|
||||
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
/// A "Label" is an identifier of some point in sources,
|
||||
/// e.g. in the following code:
|
||||
@ -94,7 +91,7 @@ pub struct Path {
|
||||
/// The segments in the path: the things separated by `::`.
|
||||
/// Global paths begin with `kw::PathRoot`.
|
||||
pub segments: Vec<PathSegment>,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
impl PartialEq<Symbol> for Path {
|
||||
@ -326,46 +323,17 @@ pub type GenericBounds = Vec<GenericBound>;
|
||||
/// Specifies the enforced ordering for generic parameters. In the future,
|
||||
/// if we wanted to relax this order, we could override `PartialEq` and
|
||||
/// `PartialOrd`, to allow the kinds to be unordered.
|
||||
#[derive(Hash, Clone, Copy)]
|
||||
#[derive(Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ParamKindOrd {
|
||||
Lifetime,
|
||||
Type,
|
||||
Const,
|
||||
// `Infer` is not actually constructed directly from the AST, but is implicitly constructed
|
||||
// during HIR lowering, and `ParamKindOrd` will implicitly order inferred variables last.
|
||||
Infer,
|
||||
TypeOrConst,
|
||||
}
|
||||
|
||||
impl Ord for ParamKindOrd {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
use ParamKindOrd::*;
|
||||
let to_int = |v| match v {
|
||||
Lifetime => 0,
|
||||
Infer | Type | Const => 1,
|
||||
};
|
||||
|
||||
to_int(*self).cmp(&to_int(*other))
|
||||
}
|
||||
}
|
||||
impl PartialOrd for ParamKindOrd {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
impl PartialEq for ParamKindOrd {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
impl Eq for ParamKindOrd {}
|
||||
|
||||
impl fmt::Display for ParamKindOrd {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ParamKindOrd::Lifetime => "lifetime".fmt(f),
|
||||
ParamKindOrd::Type => "type".fmt(f),
|
||||
ParamKindOrd::Const { .. } => "const".fmt(f),
|
||||
ParamKindOrd::Infer => "infer".fmt(f),
|
||||
ParamKindOrd::TypeOrConst => "type and const".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -497,7 +465,6 @@ pub struct WhereRegionPredicate {
|
||||
/// E.g., `T = int`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct WhereEqPredicate {
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub lhs_ty: P<Ty>,
|
||||
pub rhs_ty: P<Ty>,
|
||||
@ -505,7 +472,7 @@ pub struct WhereEqPredicate {
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Crate {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub items: Vec<P<Item>>,
|
||||
pub spans: ModSpans,
|
||||
/// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold
|
||||
@ -567,7 +534,7 @@ pub struct Block {
|
||||
/// Distinguishes between `unsafe { ... }` and `{ ... }`.
|
||||
pub rules: BlockCheckMode,
|
||||
pub span: Span,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
/// The following *isn't* a parse error, but will cause multiple errors in following stages.
|
||||
/// ```compile_fail
|
||||
/// let x = {
|
||||
@ -586,7 +553,7 @@ pub struct Pat {
|
||||
pub id: NodeId,
|
||||
pub kind: PatKind,
|
||||
pub span: Span,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
impl Pat {
|
||||
@ -597,7 +564,7 @@ impl Pat {
|
||||
// In a type expression `_` is an inference variable.
|
||||
PatKind::Wild => TyKind::Infer,
|
||||
// An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
|
||||
PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
|
||||
PatKind::Ident(BindingAnnotation::NONE, ident, None) => {
|
||||
TyKind::Path(None, Path::from_ident(*ident))
|
||||
}
|
||||
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
|
||||
@ -684,10 +651,43 @@ pub struct PatField {
|
||||
pub is_placeholder: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
|
||||
pub enum BindingMode {
|
||||
ByRef(Mutability),
|
||||
ByValue(Mutability),
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum ByRef {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl From<bool> for ByRef {
|
||||
fn from(b: bool) -> ByRef {
|
||||
match b {
|
||||
false => ByRef::No,
|
||||
true => ByRef::Yes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicit binding annotations given in the HIR for a binding. Note
|
||||
/// that this is not the final binding *mode* that we infer after type
|
||||
/// inference.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct BindingAnnotation(pub ByRef, pub Mutability);
|
||||
|
||||
impl BindingAnnotation {
|
||||
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
|
||||
pub const REF: Self = Self(ByRef::Yes, Mutability::Not);
|
||||
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
|
||||
pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut);
|
||||
|
||||
pub fn prefix_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::NONE => "",
|
||||
Self::REF => "ref ",
|
||||
Self::MUT => "mut ",
|
||||
Self::REF_MUT => "ref mut ",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
@ -716,7 +716,7 @@ pub enum PatKind {
|
||||
/// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
|
||||
/// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
|
||||
/// during name resolution.
|
||||
Ident(BindingMode, Ident, Option<P<Pat>>),
|
||||
Ident(BindingAnnotation, Ident, Option<P<Pat>>),
|
||||
|
||||
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
|
||||
/// The `bool` is `true` in the presence of a `..`.
|
||||
@ -771,7 +771,7 @@ pub enum PatKind {
|
||||
Paren(P<Pat>),
|
||||
|
||||
/// A macro pattern; pre-expansion.
|
||||
MacCall(MacCall),
|
||||
MacCall(P<MacCall>),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
|
||||
@ -937,8 +937,8 @@ impl Stmt {
|
||||
/// a trailing semicolon.
|
||||
///
|
||||
/// This only modifies the parsed AST struct, not the attached
|
||||
/// `LazyTokenStream`. The parser is responsible for calling
|
||||
/// `CreateTokenStream::add_trailing_semi` when there is actually
|
||||
/// `LazyAttrTokenStream`. The parser is responsible for calling
|
||||
/// `ToAttrTokenStream::add_trailing_semi` when there is actually
|
||||
/// a semicolon in the tokenstream.
|
||||
pub fn add_trailing_semicolon(mut self) -> Self {
|
||||
self.kind = match self.kind {
|
||||
@ -981,10 +981,10 @@ pub enum StmtKind {
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct MacCallStmt {
|
||||
pub mac: MacCall,
|
||||
pub mac: P<MacCall>,
|
||||
pub style: MacStmtStyle,
|
||||
pub attrs: AttrVec,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
|
||||
@ -1009,7 +1009,7 @@ pub struct Local {
|
||||
pub kind: LocalKind,
|
||||
pub span: Span,
|
||||
pub attrs: AttrVec,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
@ -1108,7 +1108,7 @@ pub struct Expr {
|
||||
pub kind: ExprKind,
|
||||
pub span: Span,
|
||||
pub attrs: AttrVec,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
@ -1269,7 +1269,7 @@ impl Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::Err,
|
||||
span: DUMMY_SP,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
},
|
||||
)
|
||||
@ -1439,7 +1439,7 @@ pub enum ExprKind {
|
||||
InlineAsm(P<InlineAsm>),
|
||||
|
||||
/// A macro invocation; pre-expansion.
|
||||
MacCall(MacCall),
|
||||
MacCall(P<MacCall>),
|
||||
|
||||
/// A struct literal expression.
|
||||
///
|
||||
@ -1691,7 +1691,7 @@ pub enum StrStyle {
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct Lit {
|
||||
/// The original literal token as written in source code.
|
||||
pub token: token::Lit,
|
||||
pub token_lit: token::Lit,
|
||||
/// The "semantic" representation of the literal lowered from the original tokens.
|
||||
/// Strings are unescaped, hexadecimal forms are eliminated, etc.
|
||||
/// FIXME: Remove this and only create the semantic representation during lowering to HIR.
|
||||
@ -1719,7 +1719,7 @@ impl StrLit {
|
||||
StrStyle::Raw(n) => token::StrRaw(n),
|
||||
};
|
||||
Lit {
|
||||
token: token::Lit::new(token_kind, self.symbol, self.suffix),
|
||||
token_lit: token::Lit::new(token_kind, self.symbol, self.suffix),
|
||||
span: self.span,
|
||||
kind: LitKind::Str(self.symbol_unescaped, self.style),
|
||||
}
|
||||
@ -1753,7 +1753,8 @@ pub enum LitFloatType {
|
||||
/// E.g., `"foo"`, `42`, `12.34`, or `bool`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)]
|
||||
pub enum LitKind {
|
||||
/// A string literal (`"foo"`).
|
||||
/// A string literal (`"foo"`). The symbol is unescaped, and so may differ
|
||||
/// from the original token's symbol.
|
||||
Str(Symbol, StrStyle),
|
||||
/// A byte string (`b"foo"`).
|
||||
ByteStr(Lrc<[u8]>),
|
||||
@ -1763,12 +1764,13 @@ pub enum LitKind {
|
||||
Char(char),
|
||||
/// An integer literal (`1`).
|
||||
Int(u128, LitIntType),
|
||||
/// A float literal (`1f64` or `1E10f64`).
|
||||
/// A float literal (`1f64` or `1E10f64`). Stored as a symbol rather than
|
||||
/// `f64` so that `LitKind` can impl `Eq` and `Hash`.
|
||||
Float(Symbol, LitFloatType),
|
||||
/// A boolean literal.
|
||||
Bool(bool),
|
||||
/// Placeholder for a literal that wasn't well-formed in some way.
|
||||
Err(Symbol),
|
||||
Err,
|
||||
}
|
||||
|
||||
impl LitKind {
|
||||
@ -1807,7 +1809,7 @@ impl LitKind {
|
||||
| LitKind::Int(_, LitIntType::Unsuffixed)
|
||||
| LitKind::Float(_, LitFloatType::Unsuffixed)
|
||||
| LitKind::Bool(..)
|
||||
| LitKind::Err(..) => false,
|
||||
| LitKind::Err => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1966,7 +1968,7 @@ pub struct Ty {
|
||||
pub id: NodeId,
|
||||
pub kind: TyKind,
|
||||
pub span: Span,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
impl Clone for Ty {
|
||||
@ -2042,7 +2044,7 @@ pub enum TyKind {
|
||||
/// Inferred type of a `self` or `&self` argument in a method.
|
||||
ImplicitSelf,
|
||||
/// A macro in the type position.
|
||||
MacCall(MacCall),
|
||||
MacCall(P<MacCall>),
|
||||
/// Placeholder for a kind that has failed to be defined.
|
||||
Err,
|
||||
/// Placeholder for a `va_list`.
|
||||
@ -2059,8 +2061,11 @@ impl TyKind {
|
||||
}
|
||||
|
||||
pub fn is_simple_path(&self) -> Option<Symbol> {
|
||||
if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 {
|
||||
Some(segments[0].ident.name)
|
||||
if let TyKind::Path(None, Path { segments, .. }) = &self
|
||||
&& let [segment] = &segments[..]
|
||||
&& segment.args.is_none()
|
||||
{
|
||||
Some(segment.ident.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -2071,6 +2076,7 @@ impl TyKind {
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum TraitObjectSyntax {
|
||||
Dyn,
|
||||
DynStar,
|
||||
None,
|
||||
}
|
||||
|
||||
@ -2086,15 +2092,15 @@ pub enum InlineAsmRegOrRegClass {
|
||||
bitflags::bitflags! {
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct InlineAsmOptions: u16 {
|
||||
const PURE = 1 << 0;
|
||||
const NOMEM = 1 << 1;
|
||||
const READONLY = 1 << 2;
|
||||
const PURE = 1 << 0;
|
||||
const NOMEM = 1 << 1;
|
||||
const READONLY = 1 << 2;
|
||||
const PRESERVES_FLAGS = 1 << 3;
|
||||
const NORETURN = 1 << 4;
|
||||
const NOSTACK = 1 << 5;
|
||||
const ATT_SYNTAX = 1 << 6;
|
||||
const RAW = 1 << 7;
|
||||
const MAY_UNWIND = 1 << 8;
|
||||
const NORETURN = 1 << 4;
|
||||
const NOSTACK = 1 << 5;
|
||||
const ATT_SYNTAX = 1 << 6;
|
||||
const RAW = 1 << 7;
|
||||
const MAY_UNWIND = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2230,7 +2236,7 @@ pub type ExplicitSelf = Spanned<SelfKind>;
|
||||
impl Param {
|
||||
/// Attempts to cast parameter to `ExplicitSelf`.
|
||||
pub fn to_self(&self) -> Option<ExplicitSelf> {
|
||||
if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.kind {
|
||||
if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), ident, _) = self.pat.kind {
|
||||
if ident.name == kw::SelfLower {
|
||||
return match self.ty.kind {
|
||||
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
|
||||
@ -2260,23 +2266,10 @@ impl Param {
|
||||
pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param {
|
||||
let span = eself.span.to(eself_ident.span);
|
||||
let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None });
|
||||
let param = |mutbl, ty| Param {
|
||||
attrs,
|
||||
pat: P(Pat {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
|
||||
span,
|
||||
tokens: None,
|
||||
}),
|
||||
span,
|
||||
ty,
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
};
|
||||
match eself.node {
|
||||
SelfKind::Explicit(ty, mutbl) => param(mutbl, ty),
|
||||
SelfKind::Value(mutbl) => param(mutbl, infer_ty),
|
||||
SelfKind::Region(lt, mutbl) => param(
|
||||
let (mutbl, ty) = match eself.node {
|
||||
SelfKind::Explicit(ty, mutbl) => (mutbl, ty),
|
||||
SelfKind::Value(mutbl) => (mutbl, infer_ty),
|
||||
SelfKind::Region(lt, mutbl) => (
|
||||
Mutability::Not,
|
||||
P(Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
@ -2285,6 +2278,19 @@ impl Param {
|
||||
tokens: None,
|
||||
}),
|
||||
),
|
||||
};
|
||||
Param {
|
||||
attrs,
|
||||
pat: P(Pat {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), eself_ident, None),
|
||||
span,
|
||||
tokens: None,
|
||||
}),
|
||||
span,
|
||||
ty,
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2336,9 +2342,9 @@ impl Async {
|
||||
}
|
||||
|
||||
/// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
|
||||
pub fn opt_return_id(self) -> Option<NodeId> {
|
||||
pub fn opt_return_id(self) -> Option<(NodeId, Span)> {
|
||||
match self {
|
||||
Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id),
|
||||
Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)),
|
||||
Async::No => None,
|
||||
}
|
||||
}
|
||||
@ -2522,8 +2528,8 @@ impl<S: Encoder> Encodable<S> for AttrId {
|
||||
}
|
||||
|
||||
impl<D: Decoder> Decodable<D> for AttrId {
|
||||
fn decode(_: &mut D) -> AttrId {
|
||||
crate::attr::mk_attr_id()
|
||||
default fn decode(_: &mut D) -> AttrId {
|
||||
panic!("cannot decode `AttrId` with `{}`", std::any::type_name::<D>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2531,7 +2537,7 @@ impl<D: Decoder> Decodable<D> for AttrId {
|
||||
pub struct AttrItem {
|
||||
pub path: Path,
|
||||
pub args: MacArgs,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
/// A list of attributes.
|
||||
@ -2548,10 +2554,16 @@ pub struct Attribute {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct NormalAttr {
|
||||
pub item: AttrItem,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum AttrKind {
|
||||
/// A normal attribute.
|
||||
Normal(AttrItem, Option<LazyTokenStream>),
|
||||
Normal(P<NormalAttr>),
|
||||
|
||||
/// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
|
||||
/// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
|
||||
@ -2596,13 +2608,13 @@ impl PolyTraitRef {
|
||||
pub struct Visibility {
|
||||
pub kind: VisibilityKind,
|
||||
pub span: Span,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum VisibilityKind {
|
||||
Public,
|
||||
Restricted { path: P<Path>, id: NodeId },
|
||||
Restricted { path: P<Path>, id: NodeId, shorthand: bool },
|
||||
Inherited,
|
||||
}
|
||||
|
||||
@ -2665,7 +2677,7 @@ impl VariantData {
|
||||
/// An item definition.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Item<K = ItemKind> {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub vis: Visibility,
|
||||
@ -2682,7 +2694,7 @@ pub struct Item<K = ItemKind> {
|
||||
///
|
||||
/// Note that the tokens here do not include the outer attributes, but will
|
||||
/// include inner attributes.
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
@ -2873,7 +2885,7 @@ pub enum ItemKind {
|
||||
/// A macro invocation.
|
||||
///
|
||||
/// E.g., `foo!(..)`.
|
||||
MacCall(MacCall),
|
||||
MacCall(P<MacCall>),
|
||||
|
||||
/// A macro definition.
|
||||
MacroDef(MacroDef),
|
||||
@ -2947,7 +2959,7 @@ pub enum AssocItemKind {
|
||||
/// An associated type.
|
||||
TyAlias(Box<TyAlias>),
|
||||
/// A macro expanding to associated items.
|
||||
MacCall(MacCall),
|
||||
MacCall(P<MacCall>),
|
||||
}
|
||||
|
||||
impl AssocItemKind {
|
||||
@ -2996,7 +3008,7 @@ pub enum ForeignItemKind {
|
||||
/// An foreign type.
|
||||
TyAlias(Box<TyAlias>),
|
||||
/// A macro expanding to foreign items.
|
||||
MacCall(MacCall),
|
||||
MacCall(P<MacCall>),
|
||||
}
|
||||
|
||||
impl From<ForeignItemKind> for ItemKind {
|
||||
@ -3030,22 +3042,34 @@ pub type ForeignItem = Item<ForeignItemKind>;
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
rustc_data_structures::static_assert_size!(AssocItemKind, 72);
|
||||
rustc_data_structures::static_assert_size!(Attribute, 152);
|
||||
rustc_data_structures::static_assert_size!(Block, 48);
|
||||
rustc_data_structures::static_assert_size!(Expr, 104);
|
||||
rustc_data_structures::static_assert_size!(Fn, 192);
|
||||
rustc_data_structures::static_assert_size!(ForeignItemKind, 72);
|
||||
rustc_data_structures::static_assert_size!(GenericBound, 88);
|
||||
rustc_data_structures::static_assert_size!(Generics, 72);
|
||||
rustc_data_structures::static_assert_size!(Impl, 200);
|
||||
rustc_data_structures::static_assert_size!(Item, 200);
|
||||
rustc_data_structures::static_assert_size!(ItemKind, 112);
|
||||
rustc_data_structures::static_assert_size!(Lit, 48);
|
||||
rustc_data_structures::static_assert_size!(Pat, 120);
|
||||
rustc_data_structures::static_assert_size!(Path, 40);
|
||||
rustc_data_structures::static_assert_size!(PathSegment, 24);
|
||||
rustc_data_structures::static_assert_size!(Stmt, 32);
|
||||
rustc_data_structures::static_assert_size!(Ty, 96);
|
||||
static_assert_size!(AssocItem, 104);
|
||||
static_assert_size!(AssocItemKind, 32);
|
||||
static_assert_size!(Attribute, 32);
|
||||
static_assert_size!(Block, 48);
|
||||
static_assert_size!(Expr, 104);
|
||||
static_assert_size!(ExprKind, 72);
|
||||
#[cfg(not(bootstrap))]
|
||||
static_assert_size!(Fn, 184);
|
||||
static_assert_size!(ForeignItem, 96);
|
||||
static_assert_size!(ForeignItemKind, 24);
|
||||
static_assert_size!(GenericArg, 24);
|
||||
static_assert_size!(GenericBound, 88);
|
||||
static_assert_size!(Generics, 72);
|
||||
static_assert_size!(Impl, 200);
|
||||
static_assert_size!(Item, 184);
|
||||
static_assert_size!(ItemKind, 112);
|
||||
static_assert_size!(Lit, 48);
|
||||
static_assert_size!(LitKind, 24);
|
||||
static_assert_size!(Local, 72);
|
||||
static_assert_size!(Param, 40);
|
||||
static_assert_size!(Pat, 120);
|
||||
static_assert_size!(PatKind, 96);
|
||||
static_assert_size!(Path, 40);
|
||||
static_assert_size!(PathSegment, 24);
|
||||
static_assert_size!(Stmt, 32);
|
||||
static_assert_size!(StmtKind, 16);
|
||||
static_assert_size!(Ty, 96);
|
||||
static_assert_size!(TyKind, 72);
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
use crate::ptr::P;
|
||||
use crate::token::Nonterminal;
|
||||
use crate::tokenstream::LazyTokenStream;
|
||||
use crate::tokenstream::LazyAttrTokenStream;
|
||||
use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
|
||||
use crate::{AssocItem, Expr, ForeignItem, Item, NodeId};
|
||||
use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
|
||||
@ -124,18 +124,18 @@ impl HasSpan for AttrItem {
|
||||
|
||||
/// A trait for AST nodes having (or not having) collected tokens.
|
||||
pub trait HasTokens {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream>;
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream>;
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>>;
|
||||
}
|
||||
|
||||
macro_rules! impl_has_tokens {
|
||||
($($T:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl HasTokens for $T {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
self.tokens.as_ref()
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
Some(&mut self.tokens)
|
||||
}
|
||||
}
|
||||
@ -147,10 +147,10 @@ macro_rules! impl_has_tokens_none {
|
||||
($($T:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl HasTokens for $T {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
None
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -162,25 +162,25 @@ impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path,
|
||||
impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant);
|
||||
|
||||
impl<T: AstDeref<Target: HasTokens>> HasTokens for T {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
self.ast_deref().tokens()
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
self.ast_deref_mut().tokens_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HasTokens> HasTokens for Option<T> {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
self.as_ref().and_then(|inner| inner.tokens())
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
self.as_mut().and_then(|inner| inner.tokens_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasTokens for StmtKind {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
match self {
|
||||
StmtKind::Local(local) => local.tokens.as_ref(),
|
||||
StmtKind::Item(item) => item.tokens(),
|
||||
@ -189,7 +189,7 @@ impl HasTokens for StmtKind {
|
||||
StmtKind::MacCall(mac) => mac.tokens.as_ref(),
|
||||
}
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
match self {
|
||||
StmtKind::Local(local) => Some(&mut local.tokens),
|
||||
StmtKind::Item(item) => item.tokens_mut(),
|
||||
@ -201,26 +201,26 @@ impl HasTokens for StmtKind {
|
||||
}
|
||||
|
||||
impl HasTokens for Stmt {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
self.kind.tokens()
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
self.kind.tokens_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasTokens for Attribute {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(_, tokens) => tokens.as_ref(),
|
||||
AttrKind::Normal(normal) => normal.tokens.as_ref(),
|
||||
kind @ AttrKind::DocComment(..) => {
|
||||
panic!("Called tokens on doc comment attr {:?}", kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
Some(match &mut self.kind {
|
||||
AttrKind::Normal(_, tokens) => tokens,
|
||||
AttrKind::Normal(normal) => &mut normal.tokens,
|
||||
kind @ AttrKind::DocComment(..) => {
|
||||
panic!("Called tokens_mut on doc comment attr {:?}", kind)
|
||||
}
|
||||
@ -229,7 +229,7 @@ impl HasTokens for Attribute {
|
||||
}
|
||||
|
||||
impl HasTokens for Nonterminal {
|
||||
fn tokens(&self) -> Option<&LazyTokenStream> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
match self {
|
||||
Nonterminal::NtItem(item) => item.tokens(),
|
||||
Nonterminal::NtStmt(stmt) => stmt.tokens(),
|
||||
@ -243,7 +243,7 @@ impl HasTokens for Nonterminal {
|
||||
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
|
||||
}
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
match self {
|
||||
Nonterminal::NtItem(item) => item.tokens_mut(),
|
||||
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
|
||||
@ -270,7 +270,7 @@ pub trait HasAttrs {
|
||||
/// during token collection.
|
||||
const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
|
||||
fn attrs(&self) -> &[Attribute];
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec));
|
||||
}
|
||||
|
||||
macro_rules! impl_has_attrs {
|
||||
@ -279,12 +279,13 @@ macro_rules! impl_has_attrs {
|
||||
impl HasAttrs for $T {
|
||||
const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner;
|
||||
|
||||
#[inline]
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
&self.attrs
|
||||
}
|
||||
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
VecOrAttrVec::visit(&mut self.attrs, f)
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
|
||||
f(&mut self.attrs)
|
||||
}
|
||||
}
|
||||
)+
|
||||
@ -299,7 +300,7 @@ macro_rules! impl_has_attrs_none {
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
&[]
|
||||
}
|
||||
fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
|
||||
fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {}
|
||||
}
|
||||
)+
|
||||
};
|
||||
@ -330,7 +331,7 @@ impl<T: AstDeref<Target: HasAttrs>> HasAttrs for T {
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
self.ast_deref().attrs()
|
||||
}
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
|
||||
self.ast_deref_mut().visit_attrs(f)
|
||||
}
|
||||
}
|
||||
@ -340,7 +341,7 @@ impl<T: HasAttrs> HasAttrs for Option<T> {
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
|
||||
}
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
|
||||
if let Some(inner) = self.as_mut() {
|
||||
inner.visit_attrs(f);
|
||||
}
|
||||
@ -362,13 +363,13 @@ impl HasAttrs for StmtKind {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
|
||||
match self {
|
||||
StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f),
|
||||
StmtKind::Local(local) => f(&mut local.attrs),
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
|
||||
StmtKind::Item(item) => item.visit_attrs(f),
|
||||
StmtKind::Empty => {}
|
||||
StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
|
||||
StmtKind::MacCall(mac) => f(&mut mac.attrs),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -378,38 +379,11 @@ impl HasAttrs for Stmt {
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
self.kind.attrs()
|
||||
}
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
|
||||
self.kind.visit_attrs(f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for the impls above. Abstracts over
|
||||
/// the two types of attribute fields that AST nodes
|
||||
/// may have (`Vec<Attribute>` or `AttrVec`).
|
||||
trait VecOrAttrVec {
|
||||
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
|
||||
}
|
||||
|
||||
impl VecOrAttrVec for Vec<Attribute> {
|
||||
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl VecOrAttrVec for AttrVec {
|
||||
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
visit_attrvec(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
|
||||
crate::mut_visit::visit_clobber(attrs, |attrs| {
|
||||
let mut vec = attrs.into();
|
||||
f(&mut vec);
|
||||
vec.into()
|
||||
});
|
||||
}
|
||||
|
||||
/// A newtype around an AST node that implements the traits above if the node implements them.
|
||||
pub struct AstNodeWrapper<Wrapped, Tag> {
|
||||
pub wrapped: Wrapped,
|
||||
|
||||
@ -7,18 +7,22 @@ use crate::ast::{MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind, Neste
|
||||
use crate::ast::{Path, PathSegment};
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter, Token};
|
||||
use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
|
||||
use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
|
||||
use crate::tokenstream::{LazyTokenStream, TokenStream};
|
||||
use crate::tokenstream::{LazyAttrTokenStream, TokenStream};
|
||||
use crate::util::comments;
|
||||
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_data_structures::sync::WorkerLocal;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_span::source_map::BytePos;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::iter;
|
||||
#[cfg(debug_assertions)]
|
||||
use std::ops::BitXor;
|
||||
#[cfg(debug_assertions)]
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
pub struct MarkedAttrs(GrowableBitSet<AttrId>);
|
||||
|
||||
@ -114,7 +118,7 @@ impl Attribute {
|
||||
#[inline]
|
||||
pub fn has_name(&self, name: Symbol) -> bool {
|
||||
match self.kind {
|
||||
AttrKind::Normal(ref item, _) => item.path == name,
|
||||
AttrKind::Normal(ref normal) => normal.item.path == name,
|
||||
AttrKind::DocComment(..) => false,
|
||||
}
|
||||
}
|
||||
@ -122,9 +126,9 @@ impl Attribute {
|
||||
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
match self.kind {
|
||||
AttrKind::Normal(ref item, _) => {
|
||||
if item.path.segments.len() == 1 {
|
||||
Some(item.path.segments[0].ident)
|
||||
AttrKind::Normal(ref normal) => {
|
||||
if normal.item.path.segments.len() == 1 {
|
||||
Some(normal.item.path.segments[0].ident)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -138,14 +142,16 @@ impl Attribute {
|
||||
|
||||
pub fn value_str(&self) -> Option<Symbol> {
|
||||
match self.kind {
|
||||
AttrKind::Normal(ref item, _) => item.meta_kind().and_then(|kind| kind.value_str()),
|
||||
AttrKind::Normal(ref normal) => {
|
||||
normal.item.meta_kind().and_then(|kind| kind.value_str())
|
||||
}
|
||||
AttrKind::DocComment(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
|
||||
match self.kind {
|
||||
AttrKind::Normal(ref item, _) => match item.meta_kind() {
|
||||
AttrKind::Normal(ref normal) => match normal.item.meta_kind() {
|
||||
Some(MetaItemKind::List(list)) => Some(list),
|
||||
_ => None,
|
||||
},
|
||||
@ -154,8 +160,8 @@ impl Attribute {
|
||||
}
|
||||
|
||||
pub fn is_word(&self) -> bool {
|
||||
if let AttrKind::Normal(item, _) = &self.kind {
|
||||
matches!(item.args, MacArgs::Empty)
|
||||
if let AttrKind::Normal(normal) = &self.kind {
|
||||
matches!(normal.item.args, MacArgs::Empty)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -182,13 +188,7 @@ impl MetaItem {
|
||||
}
|
||||
|
||||
pub fn value_str(&self) -> Option<Symbol> {
|
||||
match self.kind {
|
||||
MetaItemKind::NameValue(ref v) => match v.kind {
|
||||
LitKind::Str(ref s, _) => Some(*s),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
self.kind.value_str()
|
||||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
|
||||
@ -237,6 +237,9 @@ impl AttrItem {
|
||||
}
|
||||
|
||||
impl Attribute {
|
||||
/// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
|
||||
/// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
|
||||
/// a doc comment) will return `false`.
|
||||
pub fn is_doc_comment(&self) -> bool {
|
||||
match self.kind {
|
||||
AttrKind::Normal(..) => false,
|
||||
@ -244,10 +247,16 @@ impl Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
|
||||
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
|
||||
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
|
||||
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
|
||||
/// * `#[doc(...)]` returns `None`.
|
||||
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
|
||||
match self.kind {
|
||||
AttrKind::DocComment(kind, data) => Some((data, kind)),
|
||||
AttrKind::Normal(ref item, _) if item.path == sym::doc => item
|
||||
AttrKind::Normal(ref normal) if normal.item.path == sym::doc => normal
|
||||
.item
|
||||
.meta_kind()
|
||||
.and_then(|kind| kind.value_str())
|
||||
.map(|data| (data, CommentKind::Line)),
|
||||
@ -255,11 +264,15 @@ impl Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the documentation if this is a doc comment or a sugared doc comment.
|
||||
/// * `///doc` returns `Some("doc")`.
|
||||
/// * `#[doc = "doc"]` returns `Some("doc")`.
|
||||
/// * `#[doc(...)]` returns `None`.
|
||||
pub fn doc_str(&self) -> Option<Symbol> {
|
||||
match self.kind {
|
||||
AttrKind::DocComment(.., data) => Some(data),
|
||||
AttrKind::Normal(ref item, _) if item.path == sym::doc => {
|
||||
item.meta_kind().and_then(|kind| kind.value_str())
|
||||
AttrKind::Normal(ref normal) if normal.item.path == sym::doc => {
|
||||
normal.item.meta_kind().and_then(|kind| kind.value_str())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
@ -271,14 +284,14 @@ impl Attribute {
|
||||
|
||||
pub fn get_normal_item(&self) -> &AttrItem {
|
||||
match self.kind {
|
||||
AttrKind::Normal(ref item, _) => item,
|
||||
AttrKind::Normal(ref normal) => &normal.item,
|
||||
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_normal_item(self) -> AttrItem {
|
||||
match self.kind {
|
||||
AttrKind::Normal(item, _) => item,
|
||||
AttrKind::Normal(normal) => normal.into_inner().item,
|
||||
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
|
||||
}
|
||||
}
|
||||
@ -286,31 +299,30 @@ impl Attribute {
|
||||
/// Extracts the MetaItem from inside this Attribute.
|
||||
pub fn meta(&self) -> Option<MetaItem> {
|
||||
match self.kind {
|
||||
AttrKind::Normal(ref item, _) => item.meta(self.span),
|
||||
AttrKind::Normal(ref normal) => normal.item.meta(self.span),
|
||||
AttrKind::DocComment(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
||||
match self.kind {
|
||||
AttrKind::Normal(ref item, _) => item.meta_kind(),
|
||||
AttrKind::Normal(ref normal) => normal.item.meta_kind(),
|
||||
AttrKind::DocComment(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tokens(&self) -> AttrAnnotatedTokenStream {
|
||||
pub fn tokens(&self) -> TokenStream {
|
||||
match self.kind {
|
||||
AttrKind::Normal(_, ref tokens) => tokens
|
||||
AttrKind::Normal(ref normal) => normal
|
||||
.tokens
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
|
||||
.create_token_stream(),
|
||||
AttrKind::DocComment(comment_kind, data) => AttrAnnotatedTokenStream::from((
|
||||
AttrAnnotatedTokenTree::Token(Token::new(
|
||||
token::DocComment(comment_kind, self.style, data),
|
||||
self.span,
|
||||
)),
|
||||
.to_attr_token_stream()
|
||||
.to_tokenstream(),
|
||||
AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
|
||||
Token::new(token::DocComment(comment_kind, self.style, data), self.span),
|
||||
Spacing::Alone,
|
||||
)),
|
||||
)]),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,47 +352,86 @@ pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
|
||||
NestedMetaItem::MetaItem(mk_word_item(ident))
|
||||
}
|
||||
|
||||
pub(crate) fn mk_attr_id() -> AttrId {
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering;
|
||||
pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
|
||||
|
||||
static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0);
|
||||
#[cfg(debug_assertions)]
|
||||
static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX);
|
||||
|
||||
let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
|
||||
assert!(id != u32::MAX);
|
||||
AttrId::from_u32(id)
|
||||
impl AttrIdGenerator {
|
||||
pub fn new() -> Self {
|
||||
// We use `(index as u32).reverse_bits()` to initialize the
|
||||
// starting value of AttrId in each worker thread.
|
||||
// The `index` is the index of the worker thread.
|
||||
// This ensures that the AttrId generated in each thread is unique.
|
||||
AttrIdGenerator(WorkerLocal::new(|index| {
|
||||
let index: u32 = index.try_into().unwrap();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits();
|
||||
MAX_ATTR_ID.fetch_min(max_id, Ordering::Release);
|
||||
}
|
||||
|
||||
Cell::new(index.reverse_bits())
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn mk_attr_id(&self) -> AttrId {
|
||||
let id = self.0.get();
|
||||
|
||||
// Ensure the assigned attr_id does not overlap the bits
|
||||
// representing the number of threads.
|
||||
#[cfg(debug_assertions)]
|
||||
assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire));
|
||||
|
||||
self.0.set(id + 1);
|
||||
AttrId::from_u32(id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
|
||||
mk_attr_from_item(AttrItem { path, args, tokens: None }, None, style, span)
|
||||
pub fn mk_attr(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
path: Path,
|
||||
args: MacArgs,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_from_item(
|
||||
g: &AttrIdGenerator,
|
||||
item: AttrItem,
|
||||
tokens: Option<LazyTokenStream>,
|
||||
tokens: Option<LazyAttrTokenStream>,
|
||||
style: AttrStyle,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
Attribute { kind: AttrKind::Normal(item, tokens), id: mk_attr_id(), style, span }
|
||||
Attribute {
|
||||
kind: AttrKind::Normal(P(ast::NormalAttr { item, tokens })),
|
||||
id: g.mk_attr_id(),
|
||||
style,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an inner attribute with the given value and span.
|
||||
pub fn mk_attr_inner(item: MetaItem) -> Attribute {
|
||||
mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
|
||||
pub fn mk_attr_inner(g: &AttrIdGenerator, item: MetaItem) -> Attribute {
|
||||
mk_attr(g, AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
|
||||
}
|
||||
|
||||
/// Returns an outer attribute with the given value and span.
|
||||
pub fn mk_attr_outer(item: MetaItem) -> Attribute {
|
||||
mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
|
||||
pub fn mk_attr_outer(g: &AttrIdGenerator, item: MetaItem) -> Attribute {
|
||||
mk_attr(g, AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
|
||||
}
|
||||
|
||||
pub fn mk_doc_comment(
|
||||
g: &AttrIdGenerator,
|
||||
comment_kind: CommentKind,
|
||||
style: AttrStyle,
|
||||
data: Symbol,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span }
|
||||
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
|
||||
}
|
||||
|
||||
pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
|
||||
@ -484,7 +535,7 @@ impl MetaItemKind {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::Lit(lit.clone()),
|
||||
span: lit.span,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
});
|
||||
MacArgs::Eq(span, MacArgsEq::Ast(expr))
|
||||
|
||||
@ -13,17 +13,23 @@
|
||||
#![feature(const_default_impls)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(label_break_value)]
|
||||
#![cfg_attr(bootstrap, feature(label_break_value))]
|
||||
#![feature(let_chains)]
|
||||
#![cfg_attr(bootstrap, feature(let_else))]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(slice_internals)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
pub mod util {
|
||||
pub mod classify;
|
||||
pub mod comments;
|
||||
|
||||
@ -14,7 +14,6 @@ use crate::tokenstream::*;
|
||||
|
||||
use rustc_data_structures::map_in_place::MapInPlace;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::Span;
|
||||
@ -338,12 +337,7 @@ where
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_attrs<T: MutVisitor>(attrs: &mut Vec<Attribute>, vis: &mut T) {
|
||||
visit_vec(attrs, |attr| vis.visit_attribute(attr));
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_thin_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
|
||||
pub fn visit_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
|
||||
for attr in attrs.iter_mut() {
|
||||
vis.visit_attribute(attr);
|
||||
}
|
||||
@ -398,7 +392,7 @@ pub fn noop_flat_map_pat_field<T: MutVisitor>(
|
||||
vis.visit_ident(ident);
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_span(span);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
smallvec![fp]
|
||||
}
|
||||
|
||||
@ -424,7 +418,7 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
|
||||
|
||||
pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
|
||||
let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
vis.visit_id(id);
|
||||
vis.visit_pat(pat);
|
||||
visit_opt(guard, |guard| vis.visit_expr(guard));
|
||||
@ -507,7 +501,7 @@ pub fn noop_flat_map_variant<T: MutVisitor>(
|
||||
let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
|
||||
visitor.visit_ident(ident);
|
||||
visitor.visit_vis(vis);
|
||||
visit_thin_attrs(attrs, visitor);
|
||||
visit_attrs(attrs, visitor);
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_variant_data(data);
|
||||
visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
|
||||
@ -589,14 +583,16 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
|
||||
}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
}
|
||||
|
||||
pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
|
||||
let Attribute { kind, id: _, style: _, span } = attr;
|
||||
match kind {
|
||||
AttrKind::Normal(AttrItem { path, args, tokens }, attr_tokens) => {
|
||||
AttrKind::Normal(normal) => {
|
||||
let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } =
|
||||
&mut **normal;
|
||||
vis.visit_path(path);
|
||||
visit_mac_args(args, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
@ -638,7 +634,7 @@ pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
|
||||
pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> {
|
||||
let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
|
||||
vis.visit_id(id);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_span(span);
|
||||
vis.visit_ty(ty);
|
||||
@ -646,21 +642,21 @@ pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> Smal
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_attr_annotated_tt<T: MutVisitor>(tt: &mut AttrAnnotatedTokenTree, vis: &mut T) {
|
||||
pub fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) {
|
||||
match tt {
|
||||
AttrAnnotatedTokenTree::Token(token) => {
|
||||
AttrTokenTree::Token(token, _) => {
|
||||
visit_token(token, vis);
|
||||
}
|
||||
AttrAnnotatedTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
|
||||
AttrTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
|
||||
vis.visit_span(open);
|
||||
vis.visit_span(close);
|
||||
visit_attr_annotated_tts(tts, vis);
|
||||
visit_attr_tts(tts, vis);
|
||||
}
|
||||
AttrAnnotatedTokenTree::Attributes(data) => {
|
||||
AttrTokenTree::Attributes(data) => {
|
||||
for attr in &mut *data.attrs {
|
||||
match &mut attr.kind {
|
||||
AttrKind::Normal(_, attr_tokens) => {
|
||||
visit_lazy_tts(attr_tokens, vis);
|
||||
AttrKind::Normal(normal) => {
|
||||
visit_lazy_tts(&mut normal.tokens, vis);
|
||||
}
|
||||
AttrKind::DocComment(..) => {
|
||||
vis.visit_span(&mut attr.span);
|
||||
@ -694,27 +690,27 @@ pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_attr_annotated_tts<T: MutVisitor>(
|
||||
AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
|
||||
vis: &mut T,
|
||||
) {
|
||||
pub fn visit_attr_tts<T: MutVisitor>(AttrTokenStream(tts): &mut AttrTokenStream, vis: &mut T) {
|
||||
if T::VISIT_TOKENS && !tts.is_empty() {
|
||||
let tts = Lrc::make_mut(tts);
|
||||
visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
|
||||
visit_vec(tts, |tree| visit_attr_tt(tree, vis));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
|
||||
pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(
|
||||
lazy_tts: Option<&mut LazyAttrTokenStream>,
|
||||
vis: &mut T,
|
||||
) {
|
||||
if T::VISIT_TOKENS {
|
||||
if let Some(lazy_tts) = lazy_tts {
|
||||
let mut tts = lazy_tts.create_token_stream();
|
||||
visit_attr_annotated_tts(&mut tts, vis);
|
||||
*lazy_tts = LazyTokenStream::new(tts);
|
||||
let mut tts = lazy_tts.to_attr_token_stream();
|
||||
visit_attr_tts(&mut tts, vis);
|
||||
*lazy_tts = LazyAttrTokenStream::new(tts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyTokenStream>, vis: &mut T) {
|
||||
pub fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyAttrTokenStream>, vis: &mut T) {
|
||||
visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis);
|
||||
}
|
||||
|
||||
@ -880,7 +876,7 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
|
||||
if let Some(ref mut colon_span) = colon_span {
|
||||
vis.visit_span(colon_span);
|
||||
}
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
|
||||
match kind {
|
||||
GenericParamKind::Lifetime => {}
|
||||
@ -933,8 +929,7 @@ pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis:
|
||||
visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
|
||||
}
|
||||
WherePredicate::EqPredicate(ep) => {
|
||||
let WhereEqPredicate { id, span, lhs_ty, rhs_ty } = ep;
|
||||
vis.visit_id(id);
|
||||
let WhereEqPredicate { span, lhs_ty, rhs_ty } = ep;
|
||||
vis.visit_span(span);
|
||||
vis.visit_ty(lhs_ty);
|
||||
vis.visit_ty(rhs_ty);
|
||||
@ -977,7 +972,7 @@ pub fn noop_flat_map_field_def<T: MutVisitor>(
|
||||
visitor.visit_vis(vis);
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_ty(ty);
|
||||
visit_thin_attrs(attrs, visitor);
|
||||
visit_attrs(attrs, visitor);
|
||||
smallvec![fd]
|
||||
}
|
||||
|
||||
@ -990,7 +985,7 @@ pub fn noop_flat_map_expr_field<T: MutVisitor>(
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_id(id);
|
||||
vis.visit_span(span);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
smallvec![f]
|
||||
}
|
||||
|
||||
@ -1430,7 +1425,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
}
|
||||
vis.visit_id(id);
|
||||
vis.visit_span(span);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
}
|
||||
|
||||
@ -1476,7 +1471,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
|
||||
StmtKind::MacCall(mut mac) => {
|
||||
let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut();
|
||||
vis.visit_mac_call(mac_);
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_attrs(attrs, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
smallvec![StmtKind::MacCall(mac)]
|
||||
}
|
||||
@ -1486,7 +1481,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
|
||||
pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
|
||||
match &mut visibility.kind {
|
||||
VisibilityKind::Public | VisibilityKind::Inherited => {}
|
||||
VisibilityKind::Restricted { path, id } => {
|
||||
VisibilityKind::Restricted { path, id, shorthand: _ } => {
|
||||
vis.visit_path(path);
|
||||
vis.visit_id(id);
|
||||
}
|
||||
@ -1511,12 +1506,6 @@ impl<T: DummyAstNode + 'static> DummyAstNode for P<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DummyAstNode for ThinVec<T> {
|
||||
fn dummy() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl DummyAstNode for Item {
|
||||
fn dummy() -> Self {
|
||||
Item {
|
||||
|
||||
@ -13,7 +13,7 @@ rustc_index::newtype_index! {
|
||||
}
|
||||
}
|
||||
|
||||
rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeId);
|
||||
rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeMapEntry, NodeId);
|
||||
|
||||
/// The [`NodeId`] used to represent the root of the crate.
|
||||
pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0);
|
||||
|
||||
@ -398,6 +398,30 @@ impl Token {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the token can appear at the start of an pattern.
|
||||
///
|
||||
/// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
|
||||
pub fn can_begin_pattern(&self) -> bool {
|
||||
match self.uninterpolate().kind {
|
||||
Ident(name, is_raw) =>
|
||||
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
|
||||
| OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis) // tuple or array
|
||||
| Literal(..) // literal
|
||||
| BinOp(Minus) // unary minus
|
||||
| BinOp(And) // reference
|
||||
| AndAnd // double reference
|
||||
// DotDotDot is no longer supported
|
||||
| DotDot | DotDotDot | DotDotEq // ranges
|
||||
| Lt | BinOp(Shl) // associated path
|
||||
| ModSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
|
||||
NtPat(..) |
|
||||
NtBlock(..) |
|
||||
NtPath(..)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the token can appear at the start of a type.
|
||||
pub fn can_begin_type(&self) -> bool {
|
||||
match self.uninterpolate().kind {
|
||||
@ -436,6 +460,31 @@ impl Token {
|
||||
|| self == &OpenDelim(Delimiter::Parenthesis)
|
||||
}
|
||||
|
||||
/// Returns `true` if the token can appear at the start of an item.
|
||||
pub fn can_begin_item(&self) -> bool {
|
||||
match self.kind {
|
||||
Ident(name, _) => [
|
||||
kw::Fn,
|
||||
kw::Use,
|
||||
kw::Struct,
|
||||
kw::Enum,
|
||||
kw::Pub,
|
||||
kw::Trait,
|
||||
kw::Extern,
|
||||
kw::Impl,
|
||||
kw::Unsafe,
|
||||
kw::Const,
|
||||
kw::Static,
|
||||
kw::Union,
|
||||
kw::Macro,
|
||||
kw::Mod,
|
||||
kw::Type,
|
||||
]
|
||||
.contains(&name),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the token is any literal.
|
||||
pub fn is_lit(&self) -> bool {
|
||||
matches!(self.kind, Literal(..))
|
||||
|
||||
@ -121,12 +121,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CreateTokenStream: sync::Send + sync::Sync {
|
||||
fn create_token_stream(&self) -> AttrAnnotatedTokenStream;
|
||||
pub trait ToAttrTokenStream: sync::Send + sync::Sync {
|
||||
fn to_attr_token_stream(&self) -> AttrTokenStream;
|
||||
}
|
||||
|
||||
impl CreateTokenStream for AttrAnnotatedTokenStream {
|
||||
fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
|
||||
impl ToAttrTokenStream for AttrTokenStream {
|
||||
fn to_attr_token_stream(&self) -> AttrTokenStream {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
@ -135,68 +135,68 @@ impl CreateTokenStream for AttrAnnotatedTokenStream {
|
||||
/// of an actual `TokenStream` until it is needed.
|
||||
/// `Box` is here only to reduce the structure size.
|
||||
#[derive(Clone)]
|
||||
pub struct LazyTokenStream(Lrc<Box<dyn CreateTokenStream>>);
|
||||
pub struct LazyAttrTokenStream(Lrc<Box<dyn ToAttrTokenStream>>);
|
||||
|
||||
impl LazyTokenStream {
|
||||
pub fn new(inner: impl CreateTokenStream + 'static) -> LazyTokenStream {
|
||||
LazyTokenStream(Lrc::new(Box::new(inner)))
|
||||
impl LazyAttrTokenStream {
|
||||
pub fn new(inner: impl ToAttrTokenStream + 'static) -> LazyAttrTokenStream {
|
||||
LazyAttrTokenStream(Lrc::new(Box::new(inner)))
|
||||
}
|
||||
|
||||
pub fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
|
||||
self.0.create_token_stream()
|
||||
pub fn to_attr_token_stream(&self) -> AttrTokenStream {
|
||||
self.0.to_attr_token_stream()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LazyTokenStream {
|
||||
impl fmt::Debug for LazyAttrTokenStream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "LazyTokenStream({:?})", self.create_token_stream())
|
||||
write!(f, "LazyAttrTokenStream({:?})", self.to_attr_token_stream())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Encoder> Encodable<S> for LazyTokenStream {
|
||||
impl<S: Encoder> Encodable<S> for LazyAttrTokenStream {
|
||||
fn encode(&self, s: &mut S) {
|
||||
// Used by AST json printing.
|
||||
Encodable::encode(&self.create_token_stream(), s);
|
||||
Encodable::encode(&self.to_attr_token_stream(), s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Decoder> Decodable<D> for LazyTokenStream {
|
||||
impl<D: Decoder> Decodable<D> for LazyAttrTokenStream {
|
||||
fn decode(_d: &mut D) -> Self {
|
||||
panic!("Attempted to decode LazyTokenStream");
|
||||
panic!("Attempted to decode LazyAttrTokenStream");
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for LazyTokenStream {
|
||||
impl<CTX> HashStable<CTX> for LazyAttrTokenStream {
|
||||
fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
|
||||
panic!("Attempted to compute stable hash for LazyTokenStream");
|
||||
panic!("Attempted to compute stable hash for LazyAttrTokenStream");
|
||||
}
|
||||
}
|
||||
|
||||
/// A `AttrAnnotatedTokenStream` is similar to a `TokenStream`, but with extra
|
||||
/// An `AttrTokenStream` is similar to a `TokenStream`, but with extra
|
||||
/// information about the tokens for attribute targets. This is used
|
||||
/// during expansion to perform early cfg-expansion, and to process attributes
|
||||
/// during proc-macro invocations.
|
||||
#[derive(Clone, Debug, Default, Encodable, Decodable)]
|
||||
pub struct AttrAnnotatedTokenStream(pub Lrc<Vec<(AttrAnnotatedTokenTree, Spacing)>>);
|
||||
pub struct AttrTokenStream(pub Lrc<Vec<AttrTokenTree>>);
|
||||
|
||||
/// Like `TokenTree`, but for `AttrAnnotatedTokenStream`
|
||||
/// Like `TokenTree`, but for `AttrTokenStream`.
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
pub enum AttrAnnotatedTokenTree {
|
||||
Token(Token),
|
||||
Delimited(DelimSpan, Delimiter, AttrAnnotatedTokenStream),
|
||||
pub enum AttrTokenTree {
|
||||
Token(Token, Spacing),
|
||||
Delimited(DelimSpan, Delimiter, AttrTokenStream),
|
||||
/// Stores the attributes for an attribute target,
|
||||
/// along with the tokens for that attribute target.
|
||||
/// See `AttributesData` for more information
|
||||
Attributes(AttributesData),
|
||||
}
|
||||
|
||||
impl AttrAnnotatedTokenStream {
|
||||
pub fn new(tokens: Vec<(AttrAnnotatedTokenTree, Spacing)>) -> AttrAnnotatedTokenStream {
|
||||
AttrAnnotatedTokenStream(Lrc::new(tokens))
|
||||
impl AttrTokenStream {
|
||||
pub fn new(tokens: Vec<AttrTokenTree>) -> AttrTokenStream {
|
||||
AttrTokenStream(Lrc::new(tokens))
|
||||
}
|
||||
|
||||
/// Converts this `AttrAnnotatedTokenStream` to a plain `TokenStream
|
||||
/// During conversion, `AttrAnnotatedTokenTree::Attributes` get 'flattened'
|
||||
/// Converts this `AttrTokenStream` to a plain `TokenStream`.
|
||||
/// During conversion, `AttrTokenTree::Attributes` get 'flattened'
|
||||
/// back to a `TokenStream` of the form `outer_attr attr_target`.
|
||||
/// If there are inner attributes, they are inserted into the proper
|
||||
/// place in the attribute target tokens.
|
||||
@ -204,31 +204,27 @@ impl AttrAnnotatedTokenStream {
|
||||
let trees: Vec<_> = self
|
||||
.0
|
||||
.iter()
|
||||
.flat_map(|tree| match &tree.0 {
|
||||
AttrAnnotatedTokenTree::Token(inner) => {
|
||||
smallvec![TokenTree::Token(inner.clone(), tree.1)].into_iter()
|
||||
.flat_map(|tree| match &tree {
|
||||
AttrTokenTree::Token(inner, spacing) => {
|
||||
smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter()
|
||||
}
|
||||
AttrAnnotatedTokenTree::Delimited(span, delim, stream) => {
|
||||
AttrTokenTree::Delimited(span, delim, stream) => {
|
||||
smallvec![TokenTree::Delimited(*span, *delim, stream.to_tokenstream()),]
|
||||
.into_iter()
|
||||
}
|
||||
AttrAnnotatedTokenTree::Attributes(data) => {
|
||||
AttrTokenTree::Attributes(data) => {
|
||||
let mut outer_attrs = Vec::new();
|
||||
let mut inner_attrs = Vec::new();
|
||||
for attr in &data.attrs {
|
||||
match attr.style {
|
||||
crate::AttrStyle::Outer => {
|
||||
outer_attrs.push(attr);
|
||||
}
|
||||
crate::AttrStyle::Inner => {
|
||||
inner_attrs.push(attr);
|
||||
}
|
||||
crate::AttrStyle::Outer => outer_attrs.push(attr),
|
||||
crate::AttrStyle::Inner => inner_attrs.push(attr),
|
||||
}
|
||||
}
|
||||
|
||||
let mut target_tokens: Vec<_> = data
|
||||
.tokens
|
||||
.create_token_stream()
|
||||
.to_attr_token_stream()
|
||||
.to_tokenstream()
|
||||
.0
|
||||
.iter()
|
||||
@ -239,9 +235,9 @@ impl AttrAnnotatedTokenStream {
|
||||
// Check the last two trees (to account for a trailing semi)
|
||||
for tree in target_tokens.iter_mut().rev().take(2) {
|
||||
if let TokenTree::Delimited(span, delim, delim_tokens) = tree {
|
||||
// Inner attributes are only supported on extern blocks, functions, impls,
|
||||
// and modules. All of these have their inner attributes placed at
|
||||
// the beginning of the rightmost outermost braced group:
|
||||
// Inner attributes are only supported on extern blocks, functions,
|
||||
// impls, and modules. All of these have their inner attributes
|
||||
// placed at the beginning of the rightmost outermost braced group:
|
||||
// e.g. fn foo() { #![my_attr} }
|
||||
//
|
||||
// Therefore, we can insert them back into the right location
|
||||
@ -255,7 +251,7 @@ impl AttrAnnotatedTokenStream {
|
||||
|
||||
let mut builder = TokenStreamBuilder::new();
|
||||
for inner_attr in inner_attrs {
|
||||
builder.push(inner_attr.tokens().to_tokenstream());
|
||||
builder.push(inner_attr.tokens());
|
||||
}
|
||||
builder.push(delim_tokens.clone());
|
||||
*tree = TokenTree::Delimited(*span, *delim, builder.build());
|
||||
@ -273,7 +269,7 @@ impl AttrAnnotatedTokenStream {
|
||||
let mut flat: SmallVec<[_; 1]> = SmallVec::new();
|
||||
for attr in outer_attrs {
|
||||
// FIXME: Make this more efficient
|
||||
flat.extend(attr.tokens().to_tokenstream().0.clone().iter().cloned());
|
||||
flat.extend(attr.tokens().0.clone().iter().cloned());
|
||||
}
|
||||
flat.extend(target_tokens);
|
||||
flat.into_iter()
|
||||
@ -300,7 +296,7 @@ pub struct AttributesData {
|
||||
pub attrs: AttrVec,
|
||||
/// The underlying tokens for the attribute target that `attrs`
|
||||
/// are applied to
|
||||
pub tokens: LazyTokenStream,
|
||||
pub tokens: LazyAttrTokenStream,
|
||||
}
|
||||
|
||||
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
|
||||
@ -363,12 +359,6 @@ impl TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(AttrAnnotatedTokenTree, Spacing)> for AttrAnnotatedTokenStream {
|
||||
fn from((tree, spacing): (AttrAnnotatedTokenTree, Spacing)) -> AttrAnnotatedTokenStream {
|
||||
AttrAnnotatedTokenStream::new(vec![(tree, spacing)])
|
||||
}
|
||||
}
|
||||
|
||||
impl iter::FromIterator<TokenTree> for TokenStream {
|
||||
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
|
||||
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
|
||||
@ -420,21 +410,6 @@ impl TokenStream {
|
||||
TokenStream(Lrc::new(self.0.iter().enumerate().map(|(i, tree)| f(i, tree)).collect()))
|
||||
}
|
||||
|
||||
fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option<TokenStream> {
|
||||
let tokens = node.tokens()?;
|
||||
let attrs = node.attrs();
|
||||
let attr_annotated = if attrs.is_empty() {
|
||||
tokens.create_token_stream()
|
||||
} else {
|
||||
let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() };
|
||||
AttrAnnotatedTokenStream::new(vec![(
|
||||
AttrAnnotatedTokenTree::Attributes(attr_data),
|
||||
Spacing::Alone,
|
||||
)])
|
||||
};
|
||||
Some(attr_annotated.to_tokenstream())
|
||||
}
|
||||
|
||||
// Create a token stream containing a single token with alone spacing.
|
||||
pub fn token_alone(kind: TokenKind, span: Span) -> TokenStream {
|
||||
TokenStream::new(vec![TokenTree::token_alone(kind, span)])
|
||||
@ -451,8 +426,18 @@ impl TokenStream {
|
||||
}
|
||||
|
||||
pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream {
|
||||
TokenStream::opt_from_ast(node)
|
||||
.unwrap_or_else(|| panic!("missing tokens for node at {:?}: {:?}", node.span(), node))
|
||||
let Some(tokens) = node.tokens() else {
|
||||
panic!("missing tokens for node at {:?}: {:?}", node.span(), node);
|
||||
};
|
||||
let attrs = node.attrs();
|
||||
let attr_stream = if attrs.is_empty() {
|
||||
tokens.to_attr_token_stream()
|
||||
} else {
|
||||
let attr_data =
|
||||
AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
|
||||
AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)])
|
||||
};
|
||||
attr_stream.to_tokenstream()
|
||||
}
|
||||
|
||||
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
|
||||
@ -555,7 +540,7 @@ impl TokenStreamBuilder {
|
||||
|
||||
// Get the first stream, which will become the result stream.
|
||||
// If it's `None`, create an empty stream.
|
||||
let mut iter = streams.drain(..);
|
||||
let mut iter = streams.into_iter();
|
||||
let mut res_stream_lrc = iter.next().unwrap().0;
|
||||
|
||||
// Append the subsequent elements to the result stream, after
|
||||
|
||||
@ -9,7 +9,6 @@ use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::ascii;
|
||||
use tracing::debug;
|
||||
|
||||
pub enum LitError {
|
||||
NotLiteral,
|
||||
@ -23,7 +22,7 @@ pub enum LitError {
|
||||
|
||||
impl LitKind {
|
||||
/// Converts literal token into a semantic literal.
|
||||
pub fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
|
||||
pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
|
||||
let token::Lit { kind, symbol, suffix } = lit;
|
||||
if suffix.is_some() && !kind.may_have_suffix() {
|
||||
return Err(LitError::InvalidSuffix);
|
||||
@ -146,14 +145,14 @@ impl LitKind {
|
||||
|
||||
LitKind::ByteStr(bytes.into())
|
||||
}
|
||||
token::Err => LitKind::Err(symbol),
|
||||
token::Err => LitKind::Err,
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempts to recover a token from semantic literal.
|
||||
/// This function is used when the original token doesn't exist (e.g. the literal is created
|
||||
/// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
|
||||
pub fn to_lit_token(&self) -> token::Lit {
|
||||
pub fn to_token_lit(&self) -> token::Lit {
|
||||
let (kind, symbol, suffix) = match *self {
|
||||
LitKind::Str(symbol, ast::StrStyle::Cooked) => {
|
||||
// Don't re-intern unless the escaped string is different.
|
||||
@ -164,12 +163,7 @@ impl LitKind {
|
||||
}
|
||||
LitKind::Str(symbol, ast::StrStyle::Raw(n)) => (token::StrRaw(n), symbol, None),
|
||||
LitKind::ByteStr(ref bytes) => {
|
||||
let string = bytes
|
||||
.iter()
|
||||
.cloned()
|
||||
.flat_map(ascii::escape_default)
|
||||
.map(Into::<char>::into)
|
||||
.collect::<String>();
|
||||
let string = bytes.escape_ascii().to_string();
|
||||
(token::ByteStr, Symbol::intern(&string), None)
|
||||
}
|
||||
LitKind::Byte(byte) => {
|
||||
@ -199,7 +193,9 @@ impl LitKind {
|
||||
let symbol = if value { kw::True } else { kw::False };
|
||||
(token::Bool, symbol, None)
|
||||
}
|
||||
LitKind::Err(symbol) => (token::Err, symbol, None),
|
||||
// This only shows up in places like `-Zunpretty=hir` output, so we
|
||||
// don't bother to produce something useful.
|
||||
LitKind::Err => (token::Err, Symbol::intern("<bad-literal>"), None),
|
||||
};
|
||||
|
||||
token::Lit::new(kind, symbol, suffix)
|
||||
@ -208,8 +204,8 @@ impl LitKind {
|
||||
|
||||
impl Lit {
|
||||
/// Converts literal token into an AST literal.
|
||||
pub fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
|
||||
Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
|
||||
pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result<Lit, LitError> {
|
||||
Ok(Lit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span })
|
||||
}
|
||||
|
||||
/// Converts arbitrary token into an AST literal.
|
||||
@ -232,21 +228,21 @@ impl Lit {
|
||||
_ => return Err(LitError::NotLiteral),
|
||||
};
|
||||
|
||||
Lit::from_lit_token(lit, token.span)
|
||||
Lit::from_token_lit(lit, token.span)
|
||||
}
|
||||
|
||||
/// Attempts to recover an AST literal from semantic literal.
|
||||
/// This function is used when the original token doesn't exist (e.g. the literal is created
|
||||
/// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
|
||||
pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
|
||||
Lit { token: kind.to_lit_token(), kind, span }
|
||||
Lit { token_lit: kind.to_token_lit(), kind, span }
|
||||
}
|
||||
|
||||
/// Losslessly convert an AST literal into a token.
|
||||
pub fn to_token(&self) -> Token {
|
||||
let kind = match self.token.kind {
|
||||
token::Bool => token::Ident(self.token.symbol, false),
|
||||
_ => token::Literal(self.token),
|
||||
let kind = match self.token_lit.kind {
|
||||
token::Bool => token::Ident(self.token_lit.symbol, false),
|
||||
_ => token::Literal(self.token_lit),
|
||||
};
|
||||
Token::new(kind, self.span)
|
||||
}
|
||||
|
||||
@ -297,11 +297,11 @@ impl ExprPrecedence {
|
||||
match self {
|
||||
ExprPrecedence::Closure => PREC_CLOSURE,
|
||||
|
||||
ExprPrecedence::Break |
|
||||
ExprPrecedence::Continue |
|
||||
ExprPrecedence::Ret |
|
||||
ExprPrecedence::Yield |
|
||||
ExprPrecedence::Yeet => PREC_JUMP,
|
||||
ExprPrecedence::Break
|
||||
| ExprPrecedence::Continue
|
||||
| ExprPrecedence::Ret
|
||||
| ExprPrecedence::Yield
|
||||
| ExprPrecedence::Yeet => PREC_JUMP,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
@ -318,43 +318,43 @@ impl ExprPrecedence {
|
||||
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
ExprPrecedence::Box |
|
||||
ExprPrecedence::AddrOf |
|
||||
ExprPrecedence::Box
|
||||
| ExprPrecedence::AddrOf
|
||||
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
||||
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
|
||||
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
ExprPrecedence::Let |
|
||||
ExprPrecedence::Unary => PREC_PREFIX,
|
||||
| ExprPrecedence::Let
|
||||
| ExprPrecedence::Unary => PREC_PREFIX,
|
||||
|
||||
// Unary, postfix
|
||||
ExprPrecedence::Await |
|
||||
ExprPrecedence::Call |
|
||||
ExprPrecedence::MethodCall |
|
||||
ExprPrecedence::Field |
|
||||
ExprPrecedence::Index |
|
||||
ExprPrecedence::Try |
|
||||
ExprPrecedence::InlineAsm |
|
||||
ExprPrecedence::Mac => PREC_POSTFIX,
|
||||
ExprPrecedence::Await
|
||||
| ExprPrecedence::Call
|
||||
| ExprPrecedence::MethodCall
|
||||
| ExprPrecedence::Field
|
||||
| ExprPrecedence::Index
|
||||
| ExprPrecedence::Try
|
||||
| ExprPrecedence::InlineAsm
|
||||
| ExprPrecedence::Mac => PREC_POSTFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprPrecedence::Array |
|
||||
ExprPrecedence::Repeat |
|
||||
ExprPrecedence::Tup |
|
||||
ExprPrecedence::Lit |
|
||||
ExprPrecedence::Path |
|
||||
ExprPrecedence::Paren |
|
||||
ExprPrecedence::If |
|
||||
ExprPrecedence::While |
|
||||
ExprPrecedence::ForLoop |
|
||||
ExprPrecedence::Loop |
|
||||
ExprPrecedence::Match |
|
||||
ExprPrecedence::ConstBlock |
|
||||
ExprPrecedence::Block |
|
||||
ExprPrecedence::TryBlock |
|
||||
ExprPrecedence::Async |
|
||||
ExprPrecedence::Struct |
|
||||
ExprPrecedence::Err => PREC_PAREN,
|
||||
ExprPrecedence::Array
|
||||
| ExprPrecedence::Repeat
|
||||
| ExprPrecedence::Tup
|
||||
| ExprPrecedence::Lit
|
||||
| ExprPrecedence::Path
|
||||
| ExprPrecedence::Paren
|
||||
| ExprPrecedence::If
|
||||
| ExprPrecedence::While
|
||||
| ExprPrecedence::ForLoop
|
||||
| ExprPrecedence::Loop
|
||||
| ExprPrecedence::Match
|
||||
| ExprPrecedence::ConstBlock
|
||||
| ExprPrecedence::Block
|
||||
| ExprPrecedence::TryBlock
|
||||
| ExprPrecedence::Async
|
||||
| ExprPrecedence::Struct
|
||||
| ExprPrecedence::Err => PREC_PAREN,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,8 +156,8 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
|
||||
walk_where_predicate(self, p)
|
||||
}
|
||||
fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) {
|
||||
walk_fn(self, fk, s)
|
||||
fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) {
|
||||
walk_fn(self, fk)
|
||||
}
|
||||
fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) {
|
||||
walk_assoc_item(self, i, ctxt)
|
||||
@ -168,8 +168,8 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) {
|
||||
walk_param_bound(self, bounds)
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
|
||||
walk_poly_trait_ref(self, t, m)
|
||||
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
|
||||
walk_poly_trait_ref(self, t)
|
||||
}
|
||||
fn visit_variant_data(&mut self, s: &'ast VariantData) {
|
||||
walk_struct_def(self, s)
|
||||
@ -177,14 +177,8 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_field_def(&mut self, s: &'ast FieldDef) {
|
||||
walk_field_def(self, s)
|
||||
}
|
||||
fn visit_enum_def(
|
||||
&mut self,
|
||||
enum_definition: &'ast EnumDef,
|
||||
generics: &'ast Generics,
|
||||
item_id: NodeId,
|
||||
_: Span,
|
||||
) {
|
||||
walk_enum_def(self, enum_definition, generics, item_id)
|
||||
fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) {
|
||||
walk_enum_def(self, enum_definition)
|
||||
}
|
||||
fn visit_variant(&mut self, v: &'ast Variant) {
|
||||
walk_variant(self, v)
|
||||
@ -207,11 +201,11 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId, _nested: bool) {
|
||||
walk_use_tree(self, use_tree, id)
|
||||
}
|
||||
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
|
||||
walk_path_segment(self, path_span, path_segment)
|
||||
fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
|
||||
walk_path_segment(self, path_segment)
|
||||
}
|
||||
fn visit_generic_args(&mut self, path_span: Span, generic_args: &'ast GenericArgs) {
|
||||
walk_generic_args(self, path_span, generic_args)
|
||||
fn visit_generic_args(&mut self, generic_args: &'ast GenericArgs) {
|
||||
walk_generic_args(self, generic_args)
|
||||
}
|
||||
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
|
||||
walk_generic_arg(self, generic_arg)
|
||||
@ -287,11 +281,8 @@ pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime
|
||||
visitor.visit_ident(lifetime.ident);
|
||||
}
|
||||
|
||||
pub fn walk_poly_trait_ref<'a, V>(
|
||||
visitor: &mut V,
|
||||
trait_ref: &'a PolyTraitRef,
|
||||
_: &TraitBoundModifier,
|
||||
) where
|
||||
pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef)
|
||||
where
|
||||
V: Visitor<'a>,
|
||||
{
|
||||
walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
|
||||
@ -334,7 +325,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
}
|
||||
ItemKind::Enum(ref enum_definition, ref generics) => {
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
|
||||
visitor.visit_enum_def(enum_definition)
|
||||
}
|
||||
ItemKind::Impl(box Impl {
|
||||
defaultness: _,
|
||||
@ -377,12 +368,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
walk_list!(visitor, visit_attribute, &item.attrs);
|
||||
}
|
||||
|
||||
pub fn walk_enum_def<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
enum_definition: &'a EnumDef,
|
||||
_: &'a Generics,
|
||||
_: NodeId,
|
||||
) {
|
||||
pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef) {
|
||||
walk_list!(visitor, visit_variant, &enum_definition.variants);
|
||||
}
|
||||
|
||||
@ -449,7 +435,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
|
||||
|
||||
pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) {
|
||||
for segment in &path.segments {
|
||||
visitor.visit_path_segment(path.span, segment);
|
||||
visitor.visit_path_segment(segment);
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,18 +457,14 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>(visitor: &mut V, use_tree: &'a UseTree,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_path_segment<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
path_span: Span,
|
||||
segment: &'a PathSegment,
|
||||
) {
|
||||
pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V, segment: &'a PathSegment) {
|
||||
visitor.visit_ident(segment.ident);
|
||||
if let Some(ref args) = segment.args {
|
||||
visitor.visit_generic_args(path_span, args);
|
||||
visitor.visit_generic_args(args);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_generic_args<'a, V>(visitor: &mut V, _path_span: Span, generic_args: &'a GenericArgs)
|
||||
pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs)
|
||||
where
|
||||
V: Visitor<'a>,
|
||||
{
|
||||
@ -516,7 +498,7 @@ where
|
||||
pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
|
||||
visitor.visit_ident(constraint.ident);
|
||||
if let Some(ref gen_args) = constraint.gen_args {
|
||||
visitor.visit_generic_args(gen_args.span(), gen_args);
|
||||
visitor.visit_generic_args(gen_args);
|
||||
}
|
||||
match constraint.kind {
|
||||
AssocConstraintKind::Equality { ref term } => match term {
|
||||
@ -598,7 +580,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
|
||||
|
||||
pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) {
|
||||
match *bound {
|
||||
GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier),
|
||||
GenericBound::Trait(ref typ, ref _modifier) => visitor.visit_poly_trait_ref(typ),
|
||||
GenericBound::Outlives(ref lifetime) => {
|
||||
visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)
|
||||
}
|
||||
@ -673,7 +655,7 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &
|
||||
visitor.visit_fn_ret_ty(&function_declaration.output);
|
||||
}
|
||||
|
||||
pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
|
||||
pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) {
|
||||
match kind {
|
||||
FnKind::Fn(_, _, sig, _, generics, body) => {
|
||||
visitor.visit_generics(generics);
|
||||
@ -814,7 +796,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ref arguments, _span) => {
|
||||
visitor.visit_path_segment(expression.span, segment);
|
||||
visitor.visit_path_segment(segment);
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
|
||||
@ -935,14 +917,14 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
|
||||
}
|
||||
|
||||
pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) {
|
||||
if let VisibilityKind::Restricted { ref path, id } = vis.kind {
|
||||
if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind {
|
||||
visitor.visit_path(path, id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) {
|
||||
match attr.kind {
|
||||
AttrKind::Normal(ref item, ref _tokens) => walk_mac_args(visitor, &item.args),
|
||||
AttrKind::Normal(ref normal) => walk_mac_args(visitor, &normal.item.args),
|
||||
AttrKind::DocComment(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,16 +8,18 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
tracing = "0.1"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.8"
|
||||
tracing = "0.1"
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt};
|
||||
|
||||
use super::errors::{
|
||||
AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported,
|
||||
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
|
||||
InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub,
|
||||
InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber,
|
||||
RegisterConflict,
|
||||
};
|
||||
use super::LoweringContext;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
@ -26,13 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let asm_arch =
|
||||
if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch };
|
||||
if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
sp,
|
||||
E0472,
|
||||
"inline assembly is unsupported on this target"
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(InlineAsmUnsupportedTarget { span: sp });
|
||||
}
|
||||
if let Some(asm_arch) = asm_arch {
|
||||
// Inline assembly is currently only stable for these architectures.
|
||||
@ -59,10 +59,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
|
||||
&& !self.tcx.sess.opts.actually_rustdoc
|
||||
{
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(sp, "the `att_syntax` option is only supported on x86")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(AttSyntaxOnlyX86 { span: sp });
|
||||
}
|
||||
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
|
||||
feature_err(
|
||||
@ -82,51 +79,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// If the abi was already in the list, emit an error
|
||||
match clobber_abis.get(&abi) {
|
||||
Some((prev_name, prev_sp)) => {
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
*abi_span,
|
||||
&format!("`{}` ABI specified multiple times", prev_name),
|
||||
);
|
||||
err.span_label(*prev_sp, "previously specified here");
|
||||
|
||||
// Multiple different abi names may actually be the same ABI
|
||||
// If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
if source_map.span_to_snippet(*prev_sp)
|
||||
!= source_map.span_to_snippet(*abi_span)
|
||||
{
|
||||
err.note("these ABIs are equivalent on the current target");
|
||||
}
|
||||
let equivalent = (source_map.span_to_snippet(*prev_sp)
|
||||
!= source_map.span_to_snippet(*abi_span))
|
||||
.then_some(());
|
||||
|
||||
err.emit();
|
||||
self.tcx.sess.emit_err(AbiSpecifiedMultipleTimes {
|
||||
abi_span: *abi_span,
|
||||
prev_name: *prev_name,
|
||||
prev_span: *prev_sp,
|
||||
equivalent,
|
||||
});
|
||||
}
|
||||
None => {
|
||||
clobber_abis.insert(abi, (abi_name, *abi_span));
|
||||
clobber_abis.insert(abi, (*abi_name, *abi_span));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(&[]) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
*abi_span,
|
||||
"`clobber_abi` is not supported on this target",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(ClobberAbiNotSupported { abi_span: *abi_span });
|
||||
}
|
||||
Err(supported_abis) => {
|
||||
let mut err = self
|
||||
.tcx
|
||||
.sess
|
||||
.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
|
||||
let mut abis = format!("`{}`", supported_abis[0]);
|
||||
for m in &supported_abis[1..] {
|
||||
let _ = write!(abis, ", `{}`", m);
|
||||
}
|
||||
err.note(&format!(
|
||||
"the following ABIs are supported on this target: {}",
|
||||
abis
|
||||
));
|
||||
err.emit();
|
||||
self.tcx.sess.emit_err(InvalidAbiClobberAbi {
|
||||
abi_span: *abi_span,
|
||||
supported_abis: abis,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,24 +124,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.iter()
|
||||
.map(|(op, op_sp)| {
|
||||
let lower_reg = |reg| match reg {
|
||||
InlineAsmRegOrRegClass::Reg(s) => {
|
||||
InlineAsmRegOrRegClass::Reg(reg) => {
|
||||
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| {
|
||||
let msg = format!("invalid register `{}`: {}", s, e);
|
||||
sess.struct_span_err(*op_sp, &msg).emit();
|
||||
asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| {
|
||||
sess.emit_err(InvalidRegister { op_span: *op_sp, reg, error });
|
||||
asm::InlineAsmReg::Err
|
||||
})
|
||||
} else {
|
||||
asm::InlineAsmReg::Err
|
||||
})
|
||||
}
|
||||
InlineAsmRegOrRegClass::RegClass(s) => {
|
||||
InlineAsmRegOrRegClass::RegClass(reg_class) => {
|
||||
asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| {
|
||||
let msg = format!("invalid register class `{}`: {}", s, e);
|
||||
sess.struct_span_err(*op_sp, &msg).emit();
|
||||
asm::InlineAsmRegClass::Err
|
||||
})
|
||||
asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else(
|
||||
|error| {
|
||||
sess.emit_err(InvalidRegisterClass {
|
||||
op_span: *op_sp,
|
||||
reg_class,
|
||||
error,
|
||||
});
|
||||
asm::InlineAsmRegClass::Err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
asm::InlineAsmRegClass::Err
|
||||
})
|
||||
@ -168,26 +155,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let op = match *op {
|
||||
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
|
||||
reg: lower_reg(reg),
|
||||
expr: self.lower_expr_mut(expr),
|
||||
expr: self.lower_expr(expr),
|
||||
},
|
||||
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
expr: expr.as_ref().map(|expr| self.lower_expr(expr)),
|
||||
},
|
||||
InlineAsmOperand::InOut { reg, late, ref expr } => {
|
||||
hir::InlineAsmOperand::InOut {
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
expr: self.lower_expr_mut(expr),
|
||||
expr: self.lower_expr(expr),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
|
||||
hir::InlineAsmOperand::SplitInOut {
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
in_expr: self.lower_expr_mut(in_expr),
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
in_expr: self.lower_expr(in_expr),
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr(expr)),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { ref anon_const } => {
|
||||
@ -233,7 +220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&sym.qself,
|
||||
&sym.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
hir::InlineAsmOperand::SymStatic { path, def_id }
|
||||
} else {
|
||||
@ -282,50 +269,39 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
let valid_modifiers = class.valid_modifiers(asm_arch.unwrap());
|
||||
if !valid_modifiers.contains(&modifier) {
|
||||
let mut err = sess.struct_span_err(
|
||||
placeholder_span,
|
||||
"invalid asm template modifier for this register class",
|
||||
);
|
||||
err.span_label(placeholder_span, "template modifier");
|
||||
err.span_label(op_sp, "argument");
|
||||
if !valid_modifiers.is_empty() {
|
||||
let sub = if !valid_modifiers.is_empty() {
|
||||
let mut mods = format!("`{}`", valid_modifiers[0]);
|
||||
for m in &valid_modifiers[1..] {
|
||||
let _ = write!(mods, ", `{}`", m);
|
||||
}
|
||||
err.note(&format!(
|
||||
"the `{}` register class supports \
|
||||
the following template modifiers: {}",
|
||||
class.name(),
|
||||
mods
|
||||
));
|
||||
InvalidAsmTemplateModifierRegClassSub::SupportModifier {
|
||||
class_name: class.name(),
|
||||
modifiers: mods,
|
||||
}
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"the `{}` register class does not support template modifiers",
|
||||
class.name()
|
||||
));
|
||||
}
|
||||
err.emit();
|
||||
InvalidAsmTemplateModifierRegClassSub::DoesNotSupportModifier {
|
||||
class_name: class.name(),
|
||||
}
|
||||
};
|
||||
sess.emit_err(InvalidAsmTemplateModifierRegClass {
|
||||
placeholder_span,
|
||||
op_span: op_sp,
|
||||
sub,
|
||||
});
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::Const { .. } => {
|
||||
let mut err = sess.struct_span_err(
|
||||
sess.emit_err(InvalidAsmTemplateModifierConst {
|
||||
placeholder_span,
|
||||
"asm template modifiers are not allowed for `const` arguments",
|
||||
);
|
||||
err.span_label(placeholder_span, "template modifier");
|
||||
err.span_label(op_sp, "argument");
|
||||
err.emit();
|
||||
op_span: op_sp,
|
||||
});
|
||||
}
|
||||
hir::InlineAsmOperand::SymFn { .. }
|
||||
| hir::InlineAsmOperand::SymStatic { .. } => {
|
||||
let mut err = sess.struct_span_err(
|
||||
sess.emit_err(InvalidAsmTemplateModifierSym {
|
||||
placeholder_span,
|
||||
"asm template modifiers are not allowed for `sym` arguments",
|
||||
);
|
||||
err.span_label(placeholder_span, "template modifier");
|
||||
err.span_label(op_sp, "argument");
|
||||
err.emit();
|
||||
op_span: op_sp,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,12 +322,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// require that the operand name an explicit register, not a
|
||||
// register class.
|
||||
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
|
||||
let msg = format!(
|
||||
"register class `{}` can only be used as a clobber, \
|
||||
not as an input or output",
|
||||
reg_class.name()
|
||||
);
|
||||
sess.struct_span_err(op_sp, &msg).emit();
|
||||
sess.emit_err(RegisterClassOnlyClobber {
|
||||
op_span: op_sp,
|
||||
reg_class_name: reg_class.name(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -391,16 +365,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let msg = format!(
|
||||
"register `{}` conflicts with register `{}`",
|
||||
reg.name(),
|
||||
reg2.name()
|
||||
);
|
||||
let mut err = sess.struct_span_err(op_sp, &msg);
|
||||
err.span_label(op_sp, &format!("register `{}`", reg.name()));
|
||||
err.span_label(op_sp2, &format!("register `{}`", reg2.name()));
|
||||
|
||||
match (op, op2) {
|
||||
let in_out = match (op, op2) {
|
||||
(
|
||||
hir::InlineAsmOperand::In { .. },
|
||||
hir::InlineAsmOperand::Out { late, .. },
|
||||
@ -411,14 +376,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
) => {
|
||||
assert!(!*late);
|
||||
let out_op_sp = if input { op_sp2 } else { op_sp };
|
||||
let msg = "use `lateout` instead of \
|
||||
`out` to avoid conflict";
|
||||
err.span_help(out_op_sp, msg);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Some(out_op_sp)
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
err.emit();
|
||||
sess.emit_err(RegisterConflict {
|
||||
op_span1: op_sp,
|
||||
op_span2: op_sp2,
|
||||
reg1_name: reg.name(),
|
||||
reg2_name: reg2.name(),
|
||||
in_out
|
||||
});
|
||||
}
|
||||
Entry::Vacant(v) => {
|
||||
if r == reg {
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
|
||||
use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::sym;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@ -87,20 +85,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let ty = l
|
||||
.ty
|
||||
.as_ref()
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
|
||||
.map(|t| self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
|
||||
let init = l.kind.init().map(|init| self.lower_expr(init));
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
let pat = self.lower_pat(&l.pat);
|
||||
let els = if let LocalKind::InitElse(_, els) = &l.kind {
|
||||
if !self.tcx.features().let_else {
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::let_else,
|
||||
l.span,
|
||||
"`let...else` statements are unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Some(self.lower_block(els, false))
|
||||
} else {
|
||||
None
|
||||
|
||||
347
compiler/rustc_ast_lowering/src/errors.rs
Normal file
347
compiler/rustc_ast_lowering/src/errors.rs
Normal file
@ -0,0 +1,347 @@
|
||||
use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay};
|
||||
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")]
|
||||
pub struct GenericTypeWithParentheses {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<UseAngleBrackets>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UseAngleBrackets {
|
||||
pub open_param: Span,
|
||||
pub close_param: Span,
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for UseAngleBrackets {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
diag.multipart_suggestion(
|
||||
fluent::ast_lowering::use_angle_brackets,
|
||||
vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[help]
|
||||
#[diag(ast_lowering::invalid_abi, code = "E0703")]
|
||||
pub struct InvalidAbi {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub abi: Symbol,
|
||||
pub valid_abis: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::assoc_ty_parentheses)]
|
||||
pub struct AssocTyParentheses {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: AssocTyParenthesesSub,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AssocTyParenthesesSub {
|
||||
Empty { parentheses_span: Span },
|
||||
NotEmpty { open_param: Span, close_param: Span },
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for AssocTyParenthesesSub {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
match self {
|
||||
Self::Empty { parentheses_span } => diag.multipart_suggestion(
|
||||
fluent::ast_lowering::remove_parentheses,
|
||||
vec![(parentheses_span, String::new())],
|
||||
Applicability::MaybeIncorrect,
|
||||
),
|
||||
Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion(
|
||||
fluent::ast_lowering::use_angle_brackets,
|
||||
vec![(open_param, String::from("<")), (close_param, String::from(">"))],
|
||||
Applicability::MaybeIncorrect,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")]
|
||||
pub struct MisplacedImplTrait<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub position: DiagnosticArgFromDisplay<'a>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::rustc_box_attribute_error)]
|
||||
pub struct RustcBoxAttributeError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::underscore_expr_lhs_assign)]
|
||||
pub struct UnderscoreExprLhsAssign {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::base_expression_double_dot)]
|
||||
pub struct BaseExpressionDoubleDot {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")]
|
||||
pub struct AwaitOnlyInAsyncFnAndBlocks {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub dot_await_span: Span,
|
||||
#[label(ast_lowering::this_not_async)]
|
||||
pub item_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")]
|
||||
pub struct GeneratorTooManyParameters {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")]
|
||||
pub struct ClosureCannotBeStatic {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[help]
|
||||
#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")]
|
||||
pub struct AsyncNonMoveClosureNotSupported {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::functional_record_update_destructuring_assignment)]
|
||||
pub struct FunctionalRecordUpdateDestructuringAssignemnt {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::async_generators_not_supported, code = "E0727")]
|
||||
pub struct AsyncGeneratorsNotSupported {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")]
|
||||
pub struct InlineAsmUnsupportedTarget {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::att_syntax_only_x86)]
|
||||
pub struct AttSyntaxOnlyX86 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::abi_specified_multiple_times)]
|
||||
pub struct AbiSpecifiedMultipleTimes {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
pub prev_name: Symbol,
|
||||
#[label]
|
||||
pub prev_span: Span,
|
||||
#[note]
|
||||
pub equivalent: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::clobber_abi_not_supported)]
|
||||
pub struct ClobberAbiNotSupported {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[note]
|
||||
#[diag(ast_lowering::invalid_abi_clobber_abi)]
|
||||
pub struct InvalidAbiClobberAbi {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
pub supported_abis: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::invalid_register)]
|
||||
pub struct InvalidRegister<'a> {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
pub reg: Symbol,
|
||||
pub error: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::invalid_register_class)]
|
||||
pub struct InvalidRegisterClass<'a> {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
pub reg_class: Symbol,
|
||||
pub error: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)]
|
||||
pub struct InvalidAsmTemplateModifierRegClass {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering::template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering::argument)]
|
||||
pub op_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub enum InvalidAsmTemplateModifierRegClassSub {
|
||||
#[note(ast_lowering::support_modifiers)]
|
||||
SupportModifier { class_name: Symbol, modifiers: String },
|
||||
#[note(ast_lowering::does_not_support_modifiers)]
|
||||
DoesNotSupportModifier { class_name: Symbol },
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::invalid_asm_template_modifier_const)]
|
||||
pub struct InvalidAsmTemplateModifierConst {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering::template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering::argument)]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::invalid_asm_template_modifier_sym)]
|
||||
pub struct InvalidAsmTemplateModifierSym {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering::template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering::argument)]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::register_class_only_clobber)]
|
||||
pub struct RegisterClassOnlyClobber {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
pub reg_class_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::register_conflict)]
|
||||
pub struct RegisterConflict<'a> {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering::register1)]
|
||||
pub op_span1: Span,
|
||||
#[label(ast_lowering::register2)]
|
||||
pub op_span2: Span,
|
||||
pub reg1_name: &'a str,
|
||||
pub reg2_name: &'a str,
|
||||
#[help]
|
||||
pub in_out: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[help]
|
||||
#[diag(ast_lowering::sub_tuple_binding)]
|
||||
pub struct SubTupleBinding<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[suggestion_verbose(
|
||||
ast_lowering::sub_tuple_binding_suggestion,
|
||||
code = "..",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub span: Span,
|
||||
pub ident: Ident,
|
||||
pub ident_name: Symbol,
|
||||
pub ctx: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::extra_double_dot)]
|
||||
pub struct ExtraDoubleDot<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label(ast_lowering::previously_used_here)]
|
||||
pub prev_span: Span,
|
||||
pub ctx: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[note]
|
||||
#[diag(ast_lowering::misplaced_double_dot)]
|
||||
pub struct MisplacedDoubleDot {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::misplaced_relax_trait_bound)]
|
||||
pub struct MisplacedRelaxTraitBound {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)]
|
||||
pub struct NotSupportedForLifetimeBinderAsyncClosure {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::arbitrary_expression_in_pattern)]
|
||||
pub struct ArbitraryExpressionInPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::inclusive_range_with_no_end)]
|
||||
pub struct InclusiveRangeWithNoEnd {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::trait_fn_async, code = "E0706")]
|
||||
#[note]
|
||||
#[note(ast_lowering::note2)]
|
||||
pub struct TraitFnAsync {
|
||||
#[primary_span]
|
||||
pub fn_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
@ -1,19 +1,23 @@
|
||||
use super::errors::{
|
||||
AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
|
||||
GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
|
||||
RustcBoxAttributeError, UnderscoreExprLhsAssign,
|
||||
};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
||||
use crate::{FnDeclKind, ImplTraitPosition};
|
||||
|
||||
use rustc_ast::attr;
|
||||
use rustc_ast::ptr::P as AstP;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
@ -46,13 +50,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let hir_id = self.lower_node_id(e.id);
|
||||
return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
|
||||
} else {
|
||||
self.tcx.sess
|
||||
.struct_span_err(
|
||||
e.span,
|
||||
"#[rustc_box] requires precisely one argument \
|
||||
and no other attributes are allowed",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
|
||||
hir::ExprKind::Err
|
||||
}
|
||||
} else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
|
||||
@ -68,10 +66,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
seg,
|
||||
ParamMode::Optional,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
));
|
||||
let args = self.lower_exprs(args);
|
||||
hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
|
||||
let receiver = self.lower_expr(&args[0]);
|
||||
let args =
|
||||
self.arena.alloc_from_iter(args[1..].iter().map(|x| self.lower_expr_mut(x)));
|
||||
hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span))
|
||||
}
|
||||
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
||||
let binop = self.lower_binop(binop);
|
||||
@ -90,13 +90,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ExprKind::Cast(ref expr, ref ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
hir::ExprKind::Cast(expr, ty)
|
||||
}
|
||||
ExprKind::Type(ref expr, ref ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
hir::ExprKind::Type(expr, ty)
|
||||
}
|
||||
ExprKind::AddrOf(k, m, ref ohs) => {
|
||||
@ -146,13 +146,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Await(ref expr) => {
|
||||
let span = if expr.span.hi() < e.span.hi() {
|
||||
expr.span.shrink_to_hi().with_hi(e.span.hi())
|
||||
let dot_await_span = if expr.span.hi() < e.span.hi() {
|
||||
let span_with_whitespace = self
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_extend_while(expr.span, char::is_whitespace)
|
||||
.unwrap_or(expr.span);
|
||||
span_with_whitespace.shrink_to_hi().with_hi(e.span.hi())
|
||||
} else {
|
||||
// this is a recovered `await expr`
|
||||
e.span
|
||||
};
|
||||
self.lower_expr_await(span, expr)
|
||||
self.lower_expr_await(dot_await_span, expr)
|
||||
}
|
||||
ExprKind::Closure(
|
||||
ref binder,
|
||||
@ -210,13 +216,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
|
||||
}
|
||||
ExprKind::Underscore => {
|
||||
self.tcx
|
||||
.sess.struct_span_err(
|
||||
e.span,
|
||||
"in expressions, `_` can only be used on the left-hand side of an assignment",
|
||||
)
|
||||
.span_label(e.span, "`_` not allowed here")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span });
|
||||
hir::ExprKind::Err
|
||||
}
|
||||
ExprKind::Path(ref qself, ref path) => {
|
||||
@ -225,7 +225,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
hir::ExprKind::Path(qpath)
|
||||
}
|
||||
@ -248,11 +248,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let rest = match &se.rest {
|
||||
StructRest::Base(e) => Some(self.lower_expr(e)),
|
||||
StructRest::Rest(sp) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(*sp, "base expression required after `..`")
|
||||
.span_label(*sp, "add a base expression here")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp });
|
||||
Some(&*self.arena.alloc(self.expr_err(*sp)))
|
||||
}
|
||||
StructRest::None => None,
|
||||
@ -263,7 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
)),
|
||||
self.arena
|
||||
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
|
||||
@ -446,12 +442,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
|
||||
let new_cond = self.manage_let_cond(lowered_cond);
|
||||
let then = self.lower_block_expr(body);
|
||||
let expr_break = self.expr_break(span, ThinVec::new());
|
||||
let expr_break = self.expr_break(span, AttrVec::new());
|
||||
let stmt_break = self.stmt_expr(span, expr_break);
|
||||
let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
|
||||
let else_expr = self.arena.alloc(self.expr_block(else_blk, ThinVec::new()));
|
||||
let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new()));
|
||||
let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
|
||||
let if_expr = self.expr(span, if_kind, ThinVec::new());
|
||||
let if_expr = self.expr(span, if_kind, AttrVec::new());
|
||||
let block = self.block_expr(self.arena.alloc(if_expr));
|
||||
let span = self.lower_span(span.with_hi(cond.span.hi()));
|
||||
let opt_label = self.lower_label(opt_label);
|
||||
@ -510,7 +506,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let constructor = self.arena.alloc(self.expr_lang_item_path(
|
||||
method_span,
|
||||
lang_item,
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
None,
|
||||
));
|
||||
self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
|
||||
@ -562,7 +558,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = match ret_ty {
|
||||
Some(ty) => hir::FnRetTy::Return(
|
||||
self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
|
||||
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
|
||||
),
|
||||
None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
|
||||
};
|
||||
@ -587,7 +583,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (pat, task_context_hid) = self.pat_ident_binding_mode(
|
||||
span,
|
||||
Ident::with_dummy_span(sym::_task_context),
|
||||
hir::BindingAnnotation::Mutable,
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let param = hir::Param {
|
||||
hir_id: self.next_id(),
|
||||
@ -633,7 +629,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let gen_future = self.expr_lang_item_path(
|
||||
unstable_span,
|
||||
hir::LangItem::FromGenerator,
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
None,
|
||||
);
|
||||
|
||||
@ -661,17 +657,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
match self.generator_kind {
|
||||
Some(hir::GeneratorKind::Async(_)) => {}
|
||||
Some(hir::GeneratorKind::Gen) | None => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||
dot_await_span,
|
||||
E0728,
|
||||
"`await` is only allowed inside `async` functions and blocks"
|
||||
);
|
||||
err.span_label(dot_await_span, "only allowed inside `async` functions and blocks");
|
||||
if let Some(item_sp) = self.current_item {
|
||||
err.span_label(item_sp, "this is not `async`");
|
||||
}
|
||||
err.emit();
|
||||
item_span: self.current_item,
|
||||
});
|
||||
}
|
||||
}
|
||||
let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
|
||||
@ -688,7 +677,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// this name to identify what is being awaited by a suspended async functions.
|
||||
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
|
||||
let (awaitee_pat, awaitee_pat_hid) =
|
||||
self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable);
|
||||
self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::MUT);
|
||||
|
||||
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
|
||||
|
||||
@ -745,7 +734,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let break_x = self.with_loop_scope(loop_node_id, move |this| {
|
||||
let expr_break =
|
||||
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
||||
this.arena.alloc(this.expr(gen_future_span, expr_break, ThinVec::new()))
|
||||
this.arena.alloc(this.expr(gen_future_span, expr_break, AttrVec::new()))
|
||||
});
|
||||
self.arm(ready_pat, break_x)
|
||||
};
|
||||
@ -778,7 +767,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let yield_expr = self.expr(
|
||||
span,
|
||||
hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
);
|
||||
let yield_expr = self.arena.alloc(yield_expr);
|
||||
|
||||
@ -866,7 +855,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
// Lower outside new scope to preserve `is_in_loop_condition`.
|
||||
let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
|
||||
let fn_decl = self.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
@ -891,13 +880,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
match generator_kind {
|
||||
Some(hir::GeneratorKind::Gen) => {
|
||||
if decl.inputs.len() > 1 {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
fn_decl_span,
|
||||
E0628,
|
||||
"too many parameters for a generator (expected 0 or 1 parameters)"
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(GeneratorTooManyParameters { fn_decl_span });
|
||||
}
|
||||
Some(movability)
|
||||
}
|
||||
@ -906,13 +889,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
None => {
|
||||
if movability == Movability::Static {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
fn_decl_span,
|
||||
E0697,
|
||||
"closures cannot be static"
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(ClosureCannotBeStatic { fn_decl_span });
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -945,10 +922,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn_decl_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
if let &ClosureBinder::For { span, .. } = binder {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
"`for<...>` binders on `async` closures are not currently supported",
|
||||
);
|
||||
self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
||||
}
|
||||
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
@ -959,17 +933,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let body = self.with_new_scopes(|this| {
|
||||
// FIXME(cramertj): allow `async` non-`move` closures with arguments.
|
||||
if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
|
||||
struct_span_err!(
|
||||
this.tcx.sess,
|
||||
fn_decl_span,
|
||||
E0708,
|
||||
"`async` non-`move` closures with parameters are not currently supported",
|
||||
)
|
||||
.help(
|
||||
"consider using `let` statements to manually capture \
|
||||
variables by reference before entering an `async move` closure",
|
||||
)
|
||||
.emit();
|
||||
this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
|
||||
}
|
||||
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
@ -985,17 +949,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::AsyncGeneratorKind::Closure,
|
||||
|this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
|
||||
);
|
||||
this.expr(fn_decl_span, async_body, ThinVec::new())
|
||||
this.expr(fn_decl_span, async_body, AttrVec::new())
|
||||
});
|
||||
body_id
|
||||
});
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
|
||||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
// closure argument types.
|
||||
let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
|
||||
let fn_decl =
|
||||
self.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
@ -1165,11 +1129,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
// Destructure like a tuple struct.
|
||||
let tuple_struct_pat =
|
||||
hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
|
||||
let tuple_struct_pat = hir::PatKind::TupleStruct(
|
||||
qpath,
|
||||
pats,
|
||||
hir::DotDotPos::new(rest.map(|r| r.0)),
|
||||
);
|
||||
return self.pat_without_dbm(lhs.span, tuple_struct_pat);
|
||||
}
|
||||
}
|
||||
@ -1181,7 +1148,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
// Destructure like a unit struct.
|
||||
let unit_struct_pat = hir::PatKind::Path(qpath);
|
||||
@ -1205,24 +1172,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
let fields_omitted = match &se.rest {
|
||||
StructRest::Base(e) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
e.span,
|
||||
"functional record updates are not allowed in destructuring \
|
||||
assignments",
|
||||
)
|
||||
.span_suggestion(
|
||||
e.span,
|
||||
"consider removing the trailing pattern",
|
||||
"",
|
||||
rustc_errors::Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignemnt {
|
||||
span: e.span,
|
||||
});
|
||||
true
|
||||
}
|
||||
StructRest::Rest(_) => true,
|
||||
@ -1235,13 +1191,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ExprKind::Tup(elements) => {
|
||||
let (pats, rest) =
|
||||
self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
|
||||
let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
|
||||
let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));
|
||||
return self.pat_without_dbm(lhs.span, tuple_pat);
|
||||
}
|
||||
ExprKind::Paren(e) => {
|
||||
// We special-case `(..)` for consistency with patterns.
|
||||
if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
|
||||
let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
|
||||
let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));
|
||||
return self.pat_without_dbm(lhs.span, tuple_pat);
|
||||
} else {
|
||||
return self.destructure_assign_mut(e, eq_sign_span, assignments);
|
||||
@ -1255,7 +1211,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let ident = self.expr_ident(lhs.span, ident, binding);
|
||||
let assign =
|
||||
hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));
|
||||
let expr = self.expr(lhs.span, assign, ThinVec::new());
|
||||
let expr = self.expr(lhs.span, assign, AttrVec::new());
|
||||
assignments.push(self.stmt_expr(lhs.span, expr));
|
||||
pat
|
||||
}
|
||||
@ -1297,7 +1253,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let fn_path =
|
||||
hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None);
|
||||
let fn_expr =
|
||||
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
|
||||
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), AttrVec::new()));
|
||||
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
|
||||
}
|
||||
|
||||
@ -1317,7 +1273,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
(Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
|
||||
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
|
||||
(Some(..), Some(..), Closed) => unreachable!(),
|
||||
(_, None, Closed) => self.diagnostic().span_fatal(span, "inclusive range with no end"),
|
||||
(start, None, Closed) => {
|
||||
self.tcx.sess.emit_err(InclusiveRangeWithNoEnd { span });
|
||||
match start {
|
||||
Some(..) => hir::LangItem::RangeFrom,
|
||||
None => hir::LangItem::RangeFull,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let fields = self.arena.alloc_from_iter(
|
||||
@ -1404,8 +1366,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs);
|
||||
hir::ExprField {
|
||||
hir_id: self.next_id(),
|
||||
hir_id,
|
||||
ident: self.lower_ident(f.ident),
|
||||
expr: self.lower_expr(&f.expr),
|
||||
span: self.lower_span(f.span),
|
||||
@ -1417,13 +1381,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
match self.generator_kind {
|
||||
Some(hir::GeneratorKind::Gen) => {}
|
||||
Some(hir::GeneratorKind::Async(_)) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0727,
|
||||
"`async` generators are not yet supported"
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(AsyncGeneratorsNotSupported { span });
|
||||
}
|
||||
None => self.generator_kind = Some(hir::GeneratorKind::Gen),
|
||||
}
|
||||
@ -1468,7 +1426,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// `None => break`
|
||||
let none_arm = {
|
||||
let break_expr =
|
||||
self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new()));
|
||||
self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, AttrVec::new()));
|
||||
let pat = self.pat_none(for_span);
|
||||
self.arm(pat, break_expr)
|
||||
};
|
||||
@ -1477,14 +1435,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let some_arm = {
|
||||
let some_pat = self.pat_some(pat_span, pat);
|
||||
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
|
||||
let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new()));
|
||||
let body_expr = self.arena.alloc(self.expr_block(body_block, AttrVec::new()));
|
||||
self.arm(some_pat, body_expr)
|
||||
};
|
||||
|
||||
// `mut iter`
|
||||
let iter = Ident::with_dummy_span(sym::iter);
|
||||
let (iter_pat, iter_pat_nid) =
|
||||
self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
|
||||
self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT);
|
||||
|
||||
// `match Iterator::next(&mut iter) { ... }`
|
||||
let match_expr = {
|
||||
@ -1534,15 +1492,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::MatchSource::ForLoopDesugar,
|
||||
));
|
||||
|
||||
let attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect();
|
||||
|
||||
// This is effectively `{ let _result = ...; _result }`.
|
||||
// The construct was introduced in #21984 and is necessary to make sure that
|
||||
// temporaries in the `head` expression are dropped and do not leak to the
|
||||
// surrounding scope of the `match` since the `match` is not a terminating scope.
|
||||
//
|
||||
// Also, add the attributes to the outer returned expr node.
|
||||
self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
|
||||
self.expr_drop_temps_mut(for_span, match_expr, e.attrs.clone())
|
||||
}
|
||||
|
||||
/// Desugar `ExprKind::Try` from: `<expr>?` into:
|
||||
@ -1592,9 +1548,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let uc_nested = attr::mk_nested_word_item(uc_ident);
|
||||
attr::mk_list_item(allow_ident, vec![uc_nested])
|
||||
};
|
||||
attr::mk_attr_outer(allow)
|
||||
attr::mk_attr_outer(&self.tcx.sess.parse_sess.attr_id_generator, allow)
|
||||
};
|
||||
let attrs = vec![attr];
|
||||
let attrs: AttrVec = thin_vec![attr];
|
||||
|
||||
// `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
|
||||
let continue_arm = {
|
||||
@ -1604,7 +1560,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span,
|
||||
val_ident,
|
||||
val_pat_nid,
|
||||
ThinVec::from(attrs.clone()),
|
||||
attrs.clone(),
|
||||
));
|
||||
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
|
||||
self.arm(continue_pat, val_expr)
|
||||
@ -1623,7 +1579,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.arena.alloc(residual_expr),
|
||||
unstable_span,
|
||||
);
|
||||
let thin_attrs = ThinVec::from(attrs);
|
||||
let ret_expr = if let Some(catch_node) = self.catch_scope {
|
||||
let target_id = Ok(self.lower_node_id(catch_node));
|
||||
self.arena.alloc(self.expr(
|
||||
@ -1632,13 +1587,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::Destination { label: None, target_id },
|
||||
Some(from_residual_expr),
|
||||
),
|
||||
thin_attrs,
|
||||
attrs,
|
||||
))
|
||||
} else {
|
||||
self.arena.alloc(self.expr(
|
||||
try_span,
|
||||
hir::ExprKind::Ret(Some(from_residual_expr)),
|
||||
thin_attrs,
|
||||
attrs,
|
||||
))
|
||||
};
|
||||
|
||||
@ -1726,7 +1681,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
arms: &'hir [hir::Arm<'hir>],
|
||||
source: hir::MatchSource,
|
||||
) -> hir::Expr<'hir> {
|
||||
self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
|
||||
self.expr(span, hir::ExprKind::Match(arg, arms, source), AttrVec::new())
|
||||
}
|
||||
|
||||
fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> {
|
||||
@ -1743,12 +1698,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.expr(
|
||||
span,
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e),
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
)
|
||||
}
|
||||
|
||||
fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
|
||||
self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), ThinVec::new()))
|
||||
self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), AttrVec::new()))
|
||||
}
|
||||
|
||||
fn expr_call_mut(
|
||||
@ -1757,7 +1712,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
e: &'hir hir::Expr<'hir>,
|
||||
args: &'hir [hir::Expr<'hir>],
|
||||
) -> hir::Expr<'hir> {
|
||||
self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new())
|
||||
self.expr(span, hir::ExprKind::Call(e, args), AttrVec::new())
|
||||
}
|
||||
|
||||
fn expr_call(
|
||||
@ -1777,7 +1732,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir_id: Option<hir::HirId>,
|
||||
) -> hir::Expr<'hir> {
|
||||
let path =
|
||||
self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new(), hir_id));
|
||||
self.arena.alloc(self.expr_lang_item_path(span, lang_item, AttrVec::new(), hir_id));
|
||||
self.expr_call_mut(span, path, args)
|
||||
}
|
||||
|
||||
@ -1820,7 +1775,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ident: Ident,
|
||||
binding: hir::HirId,
|
||||
) -> hir::Expr<'hir> {
|
||||
self.expr_ident_with_attrs(sp, ident, binding, ThinVec::new())
|
||||
self.expr_ident_with_attrs(sp, ident, binding, AttrVec::new())
|
||||
}
|
||||
|
||||
fn expr_ident_with_attrs(
|
||||
@ -1830,12 +1785,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
binding: hir::HirId,
|
||||
attrs: AttrVec,
|
||||
) -> hir::Expr<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
let res = Res::Local(binding);
|
||||
let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
span: self.lower_span(span),
|
||||
res: Res::Local(binding),
|
||||
segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
|
||||
res,
|
||||
segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)],
|
||||
}),
|
||||
));
|
||||
|
||||
@ -1858,13 +1815,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}),
|
||||
None,
|
||||
),
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
)
|
||||
}
|
||||
|
||||
fn expr_block_empty(&mut self, span: Span) -> &'hir hir::Expr<'hir> {
|
||||
let blk = self.block_all(span, &[], None);
|
||||
let expr = self.expr_block(blk, ThinVec::new());
|
||||
let expr = self.expr_block(blk, AttrVec::new());
|
||||
self.arena.alloc(expr)
|
||||
}
|
||||
|
||||
|
||||
@ -11,8 +11,6 @@ use rustc_session::Session;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
|
||||
pub(super) struct NodeCollector<'a, 'hir> {
|
||||
/// Source map
|
||||
@ -31,7 +29,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
|
||||
definitions: &'a definitions::Definitions,
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))]
|
||||
#[instrument(level = "debug", skip(sess, definitions, bodies))]
|
||||
pub(super) fn index_hir<'hir>(
|
||||
sess: &Session,
|
||||
definitions: &definitions::Definitions,
|
||||
@ -67,10 +65,11 @@ pub(super) fn index_hir<'hir>(
|
||||
}
|
||||
|
||||
impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
|
||||
debug_assert_eq!(self.owner, hir_id.owner);
|
||||
debug_assert_ne!(hir_id.local_id.as_u32(), 0);
|
||||
debug_assert_ne!(hir_id.local_id, self.parent_node);
|
||||
|
||||
// Make sure that the DepNode of some node coincides with the HirId
|
||||
// owner of that node.
|
||||
@ -142,7 +141,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_item(&mut self, i: &'hir Item<'hir>) {
|
||||
debug_assert_eq!(i.def_id, self.owner);
|
||||
self.with_parent(i.hir_id(), |this| {
|
||||
@ -156,7 +155,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
|
||||
debug_assert_eq!(fi.def_id, self.owner);
|
||||
self.with_parent(fi.hir_id(), |this| {
|
||||
@ -175,7 +174,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
|
||||
debug_assert_eq!(ti.def_id, self.owner);
|
||||
self.with_parent(ti.hir_id(), |this| {
|
||||
@ -183,7 +182,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
|
||||
debug_assert_eq!(ii.def_id, self.owner);
|
||||
self.with_parent(ii.hir_id(), |this| {
|
||||
@ -199,6 +198,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) {
|
||||
self.insert(field.span, field.hir_id, Node::PatField(field));
|
||||
self.with_parent(field.hir_id, |this| {
|
||||
intravisit::walk_pat_field(this, field);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, arm: &'hir Arm<'hir>) {
|
||||
let node = Node::Arm(arm);
|
||||
|
||||
@ -225,6 +231,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_expr_field(&mut self, field: &'hir ExprField<'hir>) {
|
||||
self.insert(field.span, field.hir_id, Node::ExprField(field));
|
||||
self.with_parent(field.hir_id, |this| {
|
||||
intravisit::walk_expr_field(this, field);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
|
||||
self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
|
||||
|
||||
@ -233,11 +246,9 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
|
||||
if let Some(hir_id) = path_segment.hir_id {
|
||||
self.insert(path_span, hir_id, Node::PathSegment(path_segment));
|
||||
}
|
||||
intravisit::walk_path_segment(self, path_span, path_segment);
|
||||
fn visit_path_segment(&mut self, path_segment: &'hir PathSegment<'hir>) {
|
||||
self.insert(path_segment.ident.span, path_segment.hir_id, Node::PathSegment(path_segment));
|
||||
intravisit::walk_path_segment(self, path_segment);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
|
||||
@ -269,12 +280,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
fk: intravisit::FnKind<'hir>,
|
||||
fd: &'hir FnDecl<'hir>,
|
||||
b: BodyId,
|
||||
s: Span,
|
||||
_: Span,
|
||||
id: HirId,
|
||||
) {
|
||||
assert_eq!(self.owner, id.owner);
|
||||
assert_eq!(self.parent_node, id.local_id);
|
||||
intravisit::walk_fn(self, fk, fd, b, s, id);
|
||||
intravisit::walk_fn(self, fk, fd, b, id);
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &'hir Block<'hir>) {
|
||||
@ -295,14 +306,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
|
||||
fn visit_variant(&mut self, v: &'hir Variant<'hir>) {
|
||||
self.insert(v.span, v.id, Node::Variant(v));
|
||||
self.with_parent(v.id, |this| {
|
||||
// Register the constructor of this variant.
|
||||
if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
|
||||
this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
|
||||
}
|
||||
intravisit::walk_variant(this, v, g, item_id);
|
||||
intravisit::walk_variant(this, v);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use super::errors::{InvalidAbi, MisplacedRelaxTraitBound};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
|
||||
use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition};
|
||||
use super::{FnDeclKind, LoweringContext, ParamMode};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
@ -7,7 +8,6 @@ use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||
@ -25,6 +25,7 @@ use std::iter;
|
||||
pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
pub(super) tcx: TyCtxt<'hir>,
|
||||
pub(super) resolver: &'a mut ResolverAstLowering,
|
||||
pub(super) ast_arena: &'a Arena<'static>,
|
||||
pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
}
|
||||
@ -60,6 +61,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
tcx: self.tcx,
|
||||
resolver: self.resolver,
|
||||
arena: self.tcx.hir_arena,
|
||||
ast_arena: self.ast_arena,
|
||||
|
||||
// HirId handling.
|
||||
bodies: Vec::new(),
|
||||
@ -85,6 +87,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
|
||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||
allow_into_future: Some([sym::into_future][..].into()),
|
||||
generics_def_id_map: Default::default(),
|
||||
};
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
@ -120,7 +123,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
self.with_lctx(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, &c.spans);
|
||||
lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
|
||||
hir::OwnerNode::Crate(lctx.arena.alloc(module))
|
||||
hir::OwnerNode::Crate(module)
|
||||
})
|
||||
}
|
||||
|
||||
@ -158,14 +161,18 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(super) fn lower_mod(&mut self, items: &[P<Item>], spans: &ModSpans) -> hir::Mod<'hir> {
|
||||
hir::Mod {
|
||||
pub(super) fn lower_mod(
|
||||
&mut self,
|
||||
items: &[P<Item>],
|
||||
spans: &ModSpans,
|
||||
) -> &'hir hir::Mod<'hir> {
|
||||
self.arena.alloc(hir::Mod {
|
||||
spans: hir::ModSpans {
|
||||
inner_span: self.lower_span(spans.inner_span),
|
||||
inject_use_span: self.lower_span(spans.inject_use_span),
|
||||
},
|
||||
item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_ref(x))),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
|
||||
@ -259,10 +266,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let body_id =
|
||||
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
|
||||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
|
||||
let ret_id = asyncness.opt_return_id();
|
||||
this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
|
||||
this.lower_fn_decl(&decl, Some(id), fn_sig_span, FnDeclKind::Fn, ret_id)
|
||||
});
|
||||
let sig = hir::FnSig {
|
||||
decl,
|
||||
@ -306,8 +313,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, ty) = self.lower_generics(
|
||||
&generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
}
|
||||
@ -319,7 +326,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, ty) = self.lower_generics(
|
||||
&generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
@ -328,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, variants) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.arena.alloc_from_iter(
|
||||
enum_definition.variants.iter().map(|x| this.lower_variant(x)),
|
||||
@ -341,7 +348,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, struct_def) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, struct_def),
|
||||
);
|
||||
hir::ItemKind::Struct(struct_def, generics)
|
||||
@ -350,7 +357,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, vdata) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, vdata),
|
||||
);
|
||||
hir::ItemKind::Union(vdata, generics)
|
||||
@ -378,18 +385,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// method, it will not be considered an in-band
|
||||
// lifetime to be added, but rather a reference to a
|
||||
// parent lifetime.
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, id, itctx, |this| {
|
||||
self.lower_generics(ast_generics, id, &mut itctx, |this| {
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
trait_ref,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
});
|
||||
|
||||
let lowered_ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
|
||||
(trait_ref, lowered_ty)
|
||||
});
|
||||
@ -428,11 +435,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, (unsafety, items, bounds)) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let bounds = this.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
);
|
||||
let items = this.arena.alloc_from_iter(
|
||||
items.iter().map(|item| this.lower_trait_item_ref(item)),
|
||||
@ -447,11 +454,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, bounds) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
)
|
||||
},
|
||||
);
|
||||
@ -474,7 +481,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: Span,
|
||||
body: Option<&Expr>,
|
||||
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
(ty, self.lower_const_body(span, body))
|
||||
}
|
||||
|
||||
@ -647,12 +654,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
kind: match i.kind {
|
||||
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
|
||||
let fdec = &sig.decl;
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, (fn_dec, fn_args)) =
|
||||
self.lower_generics(generics, i.id, itctx, |this| {
|
||||
self.lower_generics(generics, i.id, &mut itctx, |this| {
|
||||
(
|
||||
// Disallow `impl Trait` in foreign items.
|
||||
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
|
||||
this.lower_fn_decl(
|
||||
fdec,
|
||||
None,
|
||||
sig.span,
|
||||
FnDeclKind::ExternFn,
|
||||
None,
|
||||
),
|
||||
this.lower_fn_params_to_names(fdec),
|
||||
)
|
||||
});
|
||||
@ -661,7 +674,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
ForeignItemKind::Static(ref t, m, _) => {
|
||||
let ty =
|
||||
self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
hir::ForeignItemKind::Static(ty, m)
|
||||
}
|
||||
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
|
||||
@ -729,11 +742,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
self.arena.alloc(t)
|
||||
} else {
|
||||
self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
};
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs);
|
||||
@ -756,14 +769,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let (generics, kind, has_default) = match i.kind {
|
||||
AssocItemKind::Const(_, ref ty, ref default) => {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
|
||||
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
|
||||
let asyncness = sig.header.asyncness;
|
||||
let names = self.lower_fn_params_to_names(&sig.decl);
|
||||
let (generics, sig) =
|
||||
self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
sig,
|
||||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
asyncness.opt_return_id(),
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
|
||||
@ -791,15 +810,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (generics, kind) = self.lower_generics(
|
||||
&generics,
|
||||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = ty.as_ref().map(|x| {
|
||||
this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
this.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
});
|
||||
hir::TraitItemKind::Type(
|
||||
this.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
ty,
|
||||
)
|
||||
@ -852,7 +871,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let (generics, kind) = match &i.kind {
|
||||
AssocItemKind::Const(_, ty, expr) => {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
(
|
||||
hir::Generics::empty(),
|
||||
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
|
||||
@ -879,14 +898,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_generics(
|
||||
&generics,
|
||||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| match ty {
|
||||
None => {
|
||||
let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
|
||||
hir::ImplItemKind::TyAlias(ty)
|
||||
}
|
||||
Some(ty) => {
|
||||
let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
|
||||
let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy);
|
||||
hir::ImplItemKind::TyAlias(ty)
|
||||
}
|
||||
},
|
||||
@ -947,7 +966,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
params: &'hir [hir::Param<'hir>],
|
||||
value: hir::Expr<'hir>,
|
||||
) -> hir::BodyId {
|
||||
let body = hir::Body { generator_kind: self.generator_kind, params, value };
|
||||
let body = hir::Body {
|
||||
generator_kind: self.generator_kind,
|
||||
params,
|
||||
value: self.arena.alloc(value),
|
||||
};
|
||||
let id = body.id();
|
||||
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
||||
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
|
||||
@ -1074,12 +1097,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
|
||||
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
|
||||
let (ident, is_simple_parameter) = match parameter.pat.kind {
|
||||
hir::PatKind::Binding(
|
||||
hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
|
||||
_,
|
||||
ident,
|
||||
_,
|
||||
) => (ident, true),
|
||||
hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
|
||||
(ident, true)
|
||||
}
|
||||
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
|
||||
// we can keep the same name for the parameter.
|
||||
// This lets rustdoc render it correctly in documentation.
|
||||
@ -1144,7 +1164,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (move_pat, move_id) = this.pat_ident_binding_mode(
|
||||
desugared_span,
|
||||
ident,
|
||||
hir::BindingAnnotation::Mutable,
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let move_stmt = this.stmt_let_pat(
|
||||
@ -1225,12 +1245,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
sig: &FnSig,
|
||||
id: NodeId,
|
||||
kind: FnDeclKind,
|
||||
is_async: Option<NodeId>,
|
||||
is_async: Option<(NodeId, Span)>,
|
||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header);
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
|
||||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, Some(id), sig.span, kind, is_async)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
@ -1260,10 +1280,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
fn error_on_invalid_abi(&self, abi: StrLit) {
|
||||
struct_span_err!(self.tcx.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol)
|
||||
.span_label(abi.span, "invalid ABI")
|
||||
.help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(InvalidAbi {
|
||||
span: abi.span,
|
||||
abi: abi.symbol,
|
||||
valid_abis: abi::all_names().join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync {
|
||||
@ -1294,7 +1315,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&mut self,
|
||||
generics: &Generics,
|
||||
parent_node_id: NodeId,
|
||||
itctx: ImplTraitContext,
|
||||
itctx: &ImplTraitContext,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> (&'hir hir::Generics<'hir>, T) {
|
||||
debug_assert!(self.impl_trait_defs.is_empty());
|
||||
@ -1338,11 +1359,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
let is_param = *is_param.get_or_insert_with(compute_is_param);
|
||||
if !is_param {
|
||||
self.diagnostic().span_err(
|
||||
bound.span(),
|
||||
"`?Trait` bounds are only permitted at the \
|
||||
point where a type parameter is declared",
|
||||
);
|
||||
self.tcx.sess.emit_err(MisplacedRelaxTraitBound { span: bound.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1403,7 +1420,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
id: NodeId,
|
||||
kind: &GenericParamKind,
|
||||
bounds: &[GenericBound],
|
||||
itctx: ImplTraitContext,
|
||||
itctx: &ImplTraitContext,
|
||||
origin: PredicateOrigin,
|
||||
) -> Option<hir::WherePredicate<'hir>> {
|
||||
// Do not create a clause if we do not have anything inside it.
|
||||
@ -1434,10 +1451,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
GenericParamKind::Const { .. } => None,
|
||||
GenericParamKind::Type { .. } => {
|
||||
let def_id = self.local_def_id(id).to_def_id();
|
||||
let hir_id = self.next_id();
|
||||
let res = Res::Def(DefKind::TyParam, def_id);
|
||||
let ty_path = self.arena.alloc(hir::Path {
|
||||
span: param_span,
|
||||
res: Res::Def(DefKind::TyParam, def_id),
|
||||
segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]),
|
||||
res,
|
||||
segments: self
|
||||
.arena
|
||||
.alloc_from_iter([hir::PathSegment::new(ident, hir_id, res)]),
|
||||
});
|
||||
let ty_id = self.next_id();
|
||||
let bounded_ty =
|
||||
@ -1475,11 +1496,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bound_generic_params: self.lower_generic_params(bound_generic_params),
|
||||
bounded_ty: self
|
||||
.lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||
self.lower_param_bound(
|
||||
bound,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
)
|
||||
})),
|
||||
span: self.lower_span(span),
|
||||
@ -1494,17 +1515,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
lifetime: self.lower_lifetime(lifetime),
|
||||
bounds: self.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
in_where_clause: true,
|
||||
}),
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => {
|
||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
hir_id: self.lower_node_id(id),
|
||||
lhs_ty: self
|
||||
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
.lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
rhs_ty: self
|
||||
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
.lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
span: self.lower_span(span),
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,6 @@
|
||||
use super::ResolverAstLoweringExt;
|
||||
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
|
||||
use rustc_ast::{
|
||||
FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, TraitBoundModifier, Ty,
|
||||
TyKind,
|
||||
};
|
||||
use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
|
||||
use rustc_hir::def::LifetimeRes;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::ResolverAstLowering;
|
||||
@ -66,15 +63,15 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
|
||||
self.record_lifetime_use(*lifetime);
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
|
||||
self.record_elided_anchor(path_segment.id, path_span);
|
||||
visit::walk_path_segment(self, path_span, path_segment);
|
||||
fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
|
||||
self.record_elided_anchor(path_segment.id, path_segment.ident.span);
|
||||
visit::walk_path_segment(self, path_segment);
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
|
||||
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
|
||||
self.current_binders.push(t.trait_ref.ref_id);
|
||||
|
||||
visit::walk_poly_trait_ref(self, t, m);
|
||||
visit::walk_poly_trait_ref(self, t);
|
||||
|
||||
self.current_binders.pop();
|
||||
}
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
use super::errors::{
|
||||
ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
|
||||
};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
use crate::ImplTraitPosition;
|
||||
@ -5,7 +8,6 @@ use crate::ImplTraitPosition;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_span::symbol::Ident;
|
||||
@ -22,7 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let node = loop {
|
||||
match pattern.kind {
|
||||
PatKind::Wild => break hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, ident, ref sub) => {
|
||||
PatKind::Ident(binding_mode, ident, ref sub) => {
|
||||
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
|
||||
break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
|
||||
}
|
||||
@ -35,7 +37,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
break hir::PatKind::TupleStruct(qpath, pats, ddpos);
|
||||
@ -51,7 +53,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
break hir::PatKind::Path(qpath);
|
||||
}
|
||||
@ -61,15 +63,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
|
||||
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField {
|
||||
hir_id: self.next_id(),
|
||||
ident: self.lower_ident(f.ident),
|
||||
pat: self.lower_pat(&f.pat),
|
||||
is_shorthand: f.is_shorthand,
|
||||
span: self.lower_span(f.span),
|
||||
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs);
|
||||
|
||||
hir::PatField {
|
||||
hir_id,
|
||||
ident: self.lower_ident(f.ident),
|
||||
pat: self.lower_pat(&f.pat),
|
||||
is_shorthand: f.is_shorthand,
|
||||
span: self.lower_span(f.span),
|
||||
}
|
||||
}));
|
||||
break hir::PatKind::Struct(qpath, fs, etc);
|
||||
}
|
||||
@ -109,7 +116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&mut self,
|
||||
pats: &[P<Pat>],
|
||||
ctx: &str,
|
||||
) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
|
||||
) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
|
||||
let mut elems = Vec::with_capacity(pats.len());
|
||||
let mut rest = None;
|
||||
|
||||
@ -129,20 +136,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// This is not allowed as a sub-tuple pattern
|
||||
PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
let sp = pat.span;
|
||||
self.diagnostic()
|
||||
.struct_span_err(
|
||||
sp,
|
||||
&format!("`{} @` is not allowed in a {}", ident.name, ctx),
|
||||
)
|
||||
.span_label(sp, "this is only allowed in slice patterns")
|
||||
.help("remove this and bind each tuple field independently")
|
||||
.span_suggestion_verbose(
|
||||
sp,
|
||||
&format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident),
|
||||
"..",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(SubTupleBinding {
|
||||
span: sp,
|
||||
ident_name: ident.name,
|
||||
ident,
|
||||
ctx,
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -161,7 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
(self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
|
||||
(self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
|
||||
}
|
||||
|
||||
/// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
|
||||
@ -177,9 +176,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let mut prev_rest_span = None;
|
||||
|
||||
// Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
|
||||
let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
|
||||
let lower_rest_sub = |this: &mut Self, pat, ann, ident, sub| {
|
||||
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
|
||||
let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
|
||||
let node = this.lower_pat_ident(pat, ann, ident, lower_sub);
|
||||
this.pat_with_node_id_of(pat, node)
|
||||
};
|
||||
|
||||
@ -195,9 +194,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
// Found a sub-slice pattern `$binding_mode $ident @ ..`.
|
||||
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
|
||||
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
prev_rest_span = Some(sub.span);
|
||||
slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub)));
|
||||
slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub)));
|
||||
break;
|
||||
}
|
||||
// It was not a subslice pattern so lower it normally.
|
||||
@ -210,9 +209,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// There was a previous subslice pattern; make sure we don't allow more.
|
||||
let rest_span = match pat.kind {
|
||||
PatKind::Rest => Some(pat.span),
|
||||
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
// #69103: Lower into `binding @ _` as above to avoid ICEs.
|
||||
after.push(lower_rest_sub(self, pat, bm, ident, sub));
|
||||
after.push(lower_rest_sub(self, pat, ann, ident, sub));
|
||||
Some(sub.span)
|
||||
}
|
||||
_ => None,
|
||||
@ -236,7 +235,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_pat_ident(
|
||||
&mut self,
|
||||
p: &Pat,
|
||||
binding_mode: &BindingMode,
|
||||
annotation: BindingAnnotation,
|
||||
ident: Ident,
|
||||
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
|
||||
) -> hir::PatKind<'hir> {
|
||||
@ -249,29 +248,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
};
|
||||
|
||||
hir::PatKind::Binding(
|
||||
self.lower_binding_mode(binding_mode),
|
||||
annotation,
|
||||
self.lower_node_id(canonical_id),
|
||||
self.lower_ident(ident),
|
||||
lower_sub(self),
|
||||
)
|
||||
}
|
||||
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
span: self.lower_span(ident.span),
|
||||
res: self.lower_res(res),
|
||||
segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
|
||||
}),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
|
||||
match *b {
|
||||
BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
|
||||
BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
|
||||
BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
|
||||
BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
|
||||
Some(res) => {
|
||||
let hir_id = self.next_id();
|
||||
let res = self.lower_res(res);
|
||||
hir::PatKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
span: self.lower_span(ident.span),
|
||||
res,
|
||||
segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
|
||||
}),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,19 +285,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
||||
pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
|
||||
self.diagnostic()
|
||||
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
|
||||
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
|
||||
.span_label(prev_sp, "previously used here")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx });
|
||||
}
|
||||
|
||||
/// Used to ban the `..` pattern in places it shouldn't be semantically.
|
||||
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
|
||||
self.diagnostic()
|
||||
.struct_span_err(sp, "`..` patterns are not allowed here")
|
||||
.note("only allowed in tuple, tuple struct, and slice patterns")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(MisplacedDoubleDot { span: sp });
|
||||
|
||||
// We're not in a list context so `..` can be reasonably treated
|
||||
// as `_` because it should always be valid and roughly matches the
|
||||
@ -340,8 +327,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ExprKind::Path(..) if allow_paths => {}
|
||||
ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
|
||||
_ => {
|
||||
self.diagnostic()
|
||||
.span_err(expr.span, "arbitrary expressions aren't allowed in patterns");
|
||||
self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span });
|
||||
return self.arena.alloc(self.expr_err(expr.span));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use crate::ImplTraitPosition;
|
||||
|
||||
use super::errors::{GenericTypeWithParentheses, UseAngleBrackets};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, PartialRes, Res};
|
||||
use rustc_hir::GenericArg;
|
||||
@ -13,7 +13,6 @@ use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
|
||||
use smallvec::smallvec;
|
||||
use tracing::debug;
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
@ -23,7 +22,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself: &Option<QSelf>,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
itctx: ImplTraitContext,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
@ -157,7 +156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
segment,
|
||||
param_mode,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
)
|
||||
})),
|
||||
span: self.lower_span(p.span),
|
||||
@ -181,11 +180,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
segment: &PathSegment,
|
||||
param_mode: ParamMode,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: ImplTraitContext,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
|
||||
let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
|
||||
let msg = "parenthesized type parameters may only be used with a `Fn` trait";
|
||||
match **generic_args {
|
||||
GenericArgs::AngleBracketed(ref data) => {
|
||||
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
|
||||
@ -193,10 +191,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
|
||||
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
|
||||
ParenthesizedGenericArgs::Err => {
|
||||
let mut err = struct_span_err!(self.tcx.sess, data.span, E0214, "{}", msg);
|
||||
err.span_label(data.span, "only `Fn` traits may use parentheses");
|
||||
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
|
||||
if !data.inputs.is_empty() {
|
||||
let sub = if !data.inputs.is_empty() {
|
||||
// Start of the span to the 1st character of 1st argument
|
||||
let open_param = data.inputs_span.shrink_to_lo().to(data
|
||||
.inputs
|
||||
@ -212,16 +208,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.span
|
||||
.shrink_to_hi()
|
||||
.to(data.inputs_span.shrink_to_hi());
|
||||
err.multipart_suggestion(
|
||||
&format!("use angle brackets instead",),
|
||||
vec![
|
||||
(open_param, String::from("<")),
|
||||
(close_param, String::from(">")),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
|
||||
Some(UseAngleBrackets { open_param, close_param })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.tcx.sess.emit_err(GenericTypeWithParentheses { span: data.span, sub });
|
||||
(
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
@ -258,16 +250,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
let res = self.expect_full_res(segment.id);
|
||||
let id = self.lower_node_id(segment.id);
|
||||
let hir_id = self.lower_node_id(segment.id);
|
||||
debug!(
|
||||
"lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
|
||||
segment.ident, segment.id, id,
|
||||
segment.ident, segment.id, hir_id,
|
||||
);
|
||||
|
||||
hir::PathSegment {
|
||||
ident: self.lower_ident(segment.ident),
|
||||
hir_id: Some(id),
|
||||
res: Some(self.lower_res(res)),
|
||||
hir_id,
|
||||
res: self.lower_res(res),
|
||||
infer_args,
|
||||
args: if generic_args.is_empty() && generic_args.span.is_empty() {
|
||||
None
|
||||
@ -324,7 +316,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&mut self,
|
||||
data: &AngleBracketedArgs,
|
||||
param_mode: ParamMode,
|
||||
itctx: ImplTraitContext,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
let has_non_lt_args = data.args.iter().any(|arg| match arg {
|
||||
AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
|
||||
@ -358,15 +350,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// we generally don't permit such things (see #51008).
|
||||
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
||||
self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
}));
|
||||
let output_ty = match output {
|
||||
FnRetTy::Ty(ty) => {
|
||||
self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
|
||||
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
|
||||
}
|
||||
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))];
|
||||
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
|
||||
let binding = self.output_ty_binding(output_ty.span, output_ty);
|
||||
(
|
||||
GenericArgsCtor {
|
||||
|
||||
@ -11,6 +11,7 @@ rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
||||
@ -13,9 +13,7 @@ use rustc_ast::walk_list;
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{
|
||||
error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
@ -29,6 +27,8 @@ use rustc_target::spec::abi;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
const MORE_EXTERN: &str =
|
||||
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
|
||||
|
||||
@ -121,30 +121,9 @@ impl<'a> AstValidator<'a> {
|
||||
fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
|
||||
let sess = &self.session;
|
||||
if sess.opts.unstable_features.is_nightly_build() {
|
||||
let err = "`let` expressions are not supported here";
|
||||
let mut diag = sess.struct_span_err(expr.span, err);
|
||||
diag.note("only supported directly in conditions of `if` and `while` expressions");
|
||||
match forbidden_let_reason {
|
||||
ForbiddenLetReason::GenericForbidden => {}
|
||||
ForbiddenLetReason::NotSupportedOr(span) => {
|
||||
diag.span_note(
|
||||
span,
|
||||
"`||` operators are not supported in let chain expressions",
|
||||
);
|
||||
}
|
||||
ForbiddenLetReason::NotSupportedParentheses(span) => {
|
||||
diag.span_note(
|
||||
span,
|
||||
"`let`s wrapped in parentheses are not supported in a context with let \
|
||||
chains",
|
||||
);
|
||||
}
|
||||
}
|
||||
diag.emit();
|
||||
sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
|
||||
} else {
|
||||
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
|
||||
.note("variable declaration using `let` is a statement")
|
||||
.emit();
|
||||
sess.emit_err(ForbiddenLetStable { span: expr.span });
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,7 +154,7 @@ impl<'a> AstValidator<'a> {
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
id,
|
||||
where_clauses.0.1,
|
||||
"where clause not allowed here",
|
||||
fluent::ast_passes::deprecated_where_clause_location,
|
||||
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
||||
where_clauses.1.1.shrink_to_hi(),
|
||||
suggestion,
|
||||
@ -205,10 +184,7 @@ impl<'a> AstValidator<'a> {
|
||||
AssocConstraintKind::Equality { .. } => {}
|
||||
AssocConstraintKind::Bound { .. } => {
|
||||
if self.is_assoc_ty_bound_banned {
|
||||
self.err_handler().span_err(
|
||||
constraint.span,
|
||||
"associated type bounds are not allowed within structs, enums, or unions",
|
||||
);
|
||||
self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -247,11 +223,9 @@ impl<'a> AstValidator<'a> {
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
// Allow `impl Trait` iff we're on the final path segment
|
||||
if i == path.segments.len() - 1 {
|
||||
self.visit_path_segment(path.span, segment);
|
||||
self.visit_path_segment(segment);
|
||||
} else {
|
||||
self.with_banned_impl_trait(|this| {
|
||||
this.visit_path_segment(path.span, segment)
|
||||
});
|
||||
self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -280,38 +254,33 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_lifetime(&self, ident: Ident) {
|
||||
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
|
||||
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
|
||||
self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
|
||||
self.session.emit_err(KeywordLifetime { span: ident.span });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_label(&self, ident: Ident) {
|
||||
if ident.without_first_quote().is_reserved() {
|
||||
self.err_handler()
|
||||
.span_err(ident.span, &format!("invalid label name `{}`", ident.name));
|
||||
self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
|
||||
fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
|
||||
if let VisibilityKind::Inherited = vis.kind {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut err =
|
||||
struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
|
||||
if vis.kind.is_pub() {
|
||||
err.span_label(vis.span, "`pub` not permitted here because it's implied");
|
||||
}
|
||||
if let Some(note) = note {
|
||||
err.note(note);
|
||||
}
|
||||
err.emit();
|
||||
self.session.emit_err(InvalidVisibility {
|
||||
span: vis.span,
|
||||
implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
|
||||
note,
|
||||
});
|
||||
}
|
||||
|
||||
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
||||
for Param { pat, .. } in &decl.inputs {
|
||||
match pat.kind {
|
||||
PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
|
||||
PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
|
||||
PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {}
|
||||
PatKind::Ident(BindingAnnotation::MUT, ident, None) => {
|
||||
report_err(pat.span, Some(ident), true)
|
||||
}
|
||||
_ => report_err(pat.span, None, false),
|
||||
@ -319,31 +288,9 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
|
||||
if let Async::Yes { span, .. } = asyncness {
|
||||
struct_span_err!(
|
||||
self.session,
|
||||
fn_span,
|
||||
E0706,
|
||||
"functions in traits cannot be declared `async`"
|
||||
)
|
||||
.span_label(span, "`async` because of this")
|
||||
.note("`async` trait functions are not currently supported")
|
||||
.note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||
if let Const::Yes(span) = constness {
|
||||
struct_span_err!(
|
||||
self.session,
|
||||
span,
|
||||
E0379,
|
||||
"functions in traits cannot be declared const"
|
||||
)
|
||||
.span_label(span, "functions in traits cannot be const")
|
||||
.emit();
|
||||
self.session.emit_err(TraitFnConst { span });
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,8 +303,7 @@ impl<'a> AstValidator<'a> {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.err_handler()
|
||||
.span_err(spans, "lifetime bounds cannot be used in this context");
|
||||
self.session.emit_err(ForbiddenLifetimeBound { spans });
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -365,10 +311,7 @@ impl<'a> AstValidator<'a> {
|
||||
})
|
||||
.collect();
|
||||
if !non_lt_param_spans.is_empty() {
|
||||
self.err_handler().span_err(
|
||||
non_lt_param_spans,
|
||||
"only lifetime parameters can be used in this context",
|
||||
);
|
||||
self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,10 +328,7 @@ impl<'a> AstValidator<'a> {
|
||||
let max_num_args: usize = u16::MAX.into();
|
||||
if fn_decl.inputs.len() > max_num_args {
|
||||
let Param { span, .. } = fn_decl.inputs[0];
|
||||
self.err_handler().span_fatal(
|
||||
span,
|
||||
&format!("function can not have more than {} arguments", max_num_args),
|
||||
);
|
||||
self.session.emit_fatal(FnParamTooMany { span, max_num_args });
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,19 +336,13 @@ impl<'a> AstValidator<'a> {
|
||||
match &*fn_decl.inputs {
|
||||
[Param { ty, span, .. }] => {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
self.err_handler().span_err(
|
||||
*span,
|
||||
"C-variadic function must be declared with at least one named argument",
|
||||
);
|
||||
self.session.emit_err(FnParamCVarArgsOnly { span: *span });
|
||||
}
|
||||
}
|
||||
[ps @ .., _] => {
|
||||
for Param { ty, span, .. } in ps {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
self.err_handler().span_err(
|
||||
*span,
|
||||
"`...` must be the last argument of a C-variadic function",
|
||||
);
|
||||
self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -435,19 +369,9 @@ impl<'a> AstValidator<'a> {
|
||||
})
|
||||
.for_each(|attr| {
|
||||
if attr.is_doc_comment() {
|
||||
self.err_handler()
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"documentation comments cannot be applied to function parameters",
|
||||
)
|
||||
.span_label(attr.span, "doc comments are not allowed here")
|
||||
.emit();
|
||||
self.session.emit_err(FnParamDocComment { span: attr.span });
|
||||
} else {
|
||||
self.err_handler().span_err(
|
||||
attr.span,
|
||||
"allow, cfg, cfg_attr, deny, expect, \
|
||||
forbid, and warn are the only allowed built-in attributes in function parameters",
|
||||
);
|
||||
self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -455,14 +379,7 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
|
||||
if param.is_self() {
|
||||
self.err_handler()
|
||||
.struct_span_err(
|
||||
param.span,
|
||||
"`self` parameter is only allowed in associated functions",
|
||||
)
|
||||
.span_label(param.span, "not semantically valid as function parameter")
|
||||
.note("associated functions are those in `impl` or `trait` definitions")
|
||||
.emit();
|
||||
self.session.emit_err(FnParamForbiddenSelf { span: param.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -470,47 +387,20 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||
if let Defaultness::Default(def_span) = defaultness {
|
||||
let span = self.session.source_map().guess_head_span(span);
|
||||
self.err_handler()
|
||||
.struct_span_err(span, "`default` is only allowed on items in trait impls")
|
||||
.span_label(def_span, "`default` because of this")
|
||||
.emit();
|
||||
self.session.emit_err(ForbiddenDefault { span, def_span });
|
||||
}
|
||||
}
|
||||
|
||||
fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
|
||||
self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
|
||||
}
|
||||
|
||||
fn error_item_without_body_with_help(
|
||||
&self,
|
||||
sp: Span,
|
||||
ctx: &str,
|
||||
msg: &str,
|
||||
sugg: &str,
|
||||
help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>),
|
||||
) {
|
||||
/// If `sp` ends with a semicolon, returns it as a `Span`
|
||||
/// Otherwise, returns `sp.shrink_to_hi()`
|
||||
fn ending_semi_or_hi(&self, sp: Span) -> Span {
|
||||
let source_map = self.session.source_map();
|
||||
let end = source_map.end_point(sp);
|
||||
let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
|
||||
|
||||
if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
|
||||
end
|
||||
} else {
|
||||
sp.shrink_to_hi()
|
||||
};
|
||||
let mut err = self.err_handler().struct_span_err(sp, msg);
|
||||
err.span_suggestion(
|
||||
replace_span,
|
||||
&format!("provide a definition for the {}", ctx),
|
||||
sugg,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
help(&mut err);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
|
||||
if body.is_none() {
|
||||
let msg = format!("associated {} in `impl` without body", ctx);
|
||||
self.error_item_without_body(sp, ctx, &msg, sugg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -947,10 +837,10 @@ fn validate_generic_param_order(
|
||||
let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
|
||||
let (ord_kind, ident) = match ¶m.kind {
|
||||
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
|
||||
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
|
||||
GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()),
|
||||
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
|
||||
let ty = pprust::ty_to_string(ty);
|
||||
(ParamKindOrd::Const, format!("const {}: {}", ident, ty))
|
||||
(ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
|
||||
}
|
||||
};
|
||||
param_idents.push((kind, ord_kind, bounds, idx, ident));
|
||||
@ -1180,7 +1070,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|
||||
self.invalid_visibility(
|
||||
&item.vis,
|
||||
Some("place qualifiers on individual impl items instead"),
|
||||
Some(InvalidVisibilityNote::IndividualImplItems),
|
||||
);
|
||||
if let Unsafe::Yes(span) = unsafety {
|
||||
error(span, "unsafe").code(error_code!(E0197)).emit();
|
||||
@ -1203,37 +1093,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.check_defaultness(item.span, defaultness);
|
||||
|
||||
if body.is_none() {
|
||||
let msg = "free function without a body";
|
||||
let ext = sig.header.ext;
|
||||
|
||||
let f = |e: &mut DiagnosticBuilder<'_, _>| {
|
||||
if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
|
||||
{
|
||||
let start_suggestion = if let Extern::Explicit(abi, _) = ext {
|
||||
format!("extern \"{}\" {{", abi.symbol_unescaped)
|
||||
} else {
|
||||
"extern {".to_owned()
|
||||
};
|
||||
|
||||
let end_suggestion = " }".to_owned();
|
||||
let end_span = item.span.shrink_to_hi();
|
||||
|
||||
e
|
||||
.multipart_suggestion(
|
||||
"if you meant to declare an externally defined function, use an `extern` block",
|
||||
vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
self.error_item_without_body_with_help(
|
||||
item.span,
|
||||
"function",
|
||||
msg,
|
||||
" { <body> }",
|
||||
f,
|
||||
);
|
||||
self.session.emit_err(FnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
extern_block_suggestion: match sig.header.ext {
|
||||
Extern::None => None,
|
||||
Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
|
||||
start_span,
|
||||
end_span: item.span.shrink_to_hi(),
|
||||
abi: None,
|
||||
}),
|
||||
Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
|
||||
start_span,
|
||||
end_span: item.span.shrink_to_hi(),
|
||||
abi: Some(abi.symbol_unescaped),
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
self.visit_vis(&item.vis);
|
||||
@ -1248,7 +1124,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||
self.invalid_visibility(
|
||||
&item.vis,
|
||||
Some("place qualifiers on individual foreign items instead"),
|
||||
Some(InvalidVisibilityNote::IndividualForeignItems),
|
||||
);
|
||||
if let Unsafe::Yes(span) = unsafety {
|
||||
self.err_handler().span_err(span, "extern block cannot be declared unsafe");
|
||||
@ -1339,12 +1215,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
ItemKind::Const(def, .., None) => {
|
||||
self.check_defaultness(item.span, def);
|
||||
let msg = "free constant item without body";
|
||||
self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
|
||||
self.session.emit_err(ConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
ItemKind::Static(.., None) => {
|
||||
let msg = "free static item without body";
|
||||
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
|
||||
self.session.emit_err(StaticWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
ItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
@ -1355,8 +1235,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}) => {
|
||||
self.check_defaultness(item.span, defaultness);
|
||||
if ty.is_none() {
|
||||
let msg = "free type alias without body";
|
||||
self.error_item_without_body(item.span, "type", msg, " = <type>;");
|
||||
self.session.emit_err(TyAliasWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
self.check_type_no_bounds(bounds, "this context");
|
||||
if where_clauses.1.0 {
|
||||
@ -1409,7 +1291,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
// Mirrors `visit::walk_generic_args`, but tracks relevant state.
|
||||
fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
|
||||
fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
|
||||
match *generic_args {
|
||||
GenericArgs::AngleBracketed(ref data) => {
|
||||
self.check_generic_args_before_constraints(data);
|
||||
@ -1548,25 +1430,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
visit::walk_param_bound(self, bound)
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
|
||||
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
|
||||
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
|
||||
visit::walk_poly_trait_ref(self, t, m);
|
||||
visit::walk_poly_trait_ref(self, t);
|
||||
}
|
||||
|
||||
fn visit_variant_data(&mut self, s: &'a VariantData) {
|
||||
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
|
||||
}
|
||||
|
||||
fn visit_enum_def(
|
||||
&mut self,
|
||||
enum_definition: &'a EnumDef,
|
||||
generics: &'a Generics,
|
||||
item_id: NodeId,
|
||||
_: Span,
|
||||
) {
|
||||
self.with_banned_assoc_ty_bound(|this| {
|
||||
visit::walk_enum_def(this, enum_definition, generics, item_id)
|
||||
})
|
||||
fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
|
||||
self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
|
||||
@ -1653,7 +1527,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
|
||||
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
|
||||
|
||||
self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
|
||||
self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk));
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
@ -1668,10 +1542,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
if ctxt == AssocCtxt::Impl {
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(_, _, body) => {
|
||||
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
|
||||
if body.is_none() {
|
||||
self.session.emit_err(AssocConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
|
||||
if body.is_none() {
|
||||
self.session.emit_err(AssocFnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias {
|
||||
generics,
|
||||
@ -1681,7 +1565,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
ty,
|
||||
..
|
||||
}) => {
|
||||
self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
|
||||
if ty.is_none() {
|
||||
self.session.emit_err(AssocTypeWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
self.check_type_no_bounds(bounds, "`impl`s");
|
||||
if ty.is_some() {
|
||||
self.check_gat_where(
|
||||
@ -1699,7 +1588,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.invalid_visibility(&item.vis, None);
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1896,14 +1784,14 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
|
||||
|
||||
/// Used to forbid `let` expressions in certain syntactic locations.
|
||||
#[derive(Clone, Copy)]
|
||||
enum ForbiddenLetReason {
|
||||
pub(crate) enum ForbiddenLetReason {
|
||||
/// `let` is not valid and the source environment is not important
|
||||
GenericForbidden,
|
||||
/// A let chain with the `||` operator
|
||||
NotSupportedOr(Span),
|
||||
/// A let chain with invalid parentheses
|
||||
///
|
||||
/// For exemple, `let 1 = 1 && (expr && expr)` is allowed
|
||||
/// For example, `let 1 = 1 && (expr && expr)` is allowed
|
||||
/// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
|
||||
NotSupportedParentheses(Span),
|
||||
}
|
||||
|
||||
245
compiler/rustc_ast_passes/src/errors.rs
Normal file
245
compiler/rustc_ast_passes/src/errors.rs
Normal file
@ -0,0 +1,245 @@
|
||||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic};
|
||||
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::ast_validation::ForbiddenLetReason;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_let)]
|
||||
#[note]
|
||||
pub struct ForbiddenLet {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) reason: ForbiddenLetReason,
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for ForbiddenLetReason {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
match self {
|
||||
Self::GenericForbidden => {}
|
||||
Self::NotSupportedOr(span) => {
|
||||
diag.span_note(span, fluent::ast_passes::not_supported_or);
|
||||
}
|
||||
Self::NotSupportedParentheses(span) => {
|
||||
diag.span_note(span, fluent::ast_passes::not_supported_parentheses);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_let_stable)]
|
||||
#[note]
|
||||
pub struct ForbiddenLetStable {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_assoc_constraint)]
|
||||
pub struct ForbiddenAssocConstraint {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::keyword_lifetime)]
|
||||
pub struct KeywordLifetime {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::invalid_label)]
|
||||
pub struct InvalidLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::invalid_visibility, code = "E0449")]
|
||||
pub struct InvalidVisibility {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label(ast_passes::implied)]
|
||||
pub implied: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub note: Option<InvalidVisibilityNote>,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub enum InvalidVisibilityNote {
|
||||
#[note(ast_passes::individual_impl_items)]
|
||||
IndividualImplItems,
|
||||
#[note(ast_passes::individual_foreign_items)]
|
||||
IndividualForeignItems,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::trait_fn_const, code = "E0379")]
|
||||
pub struct TraitFnConst {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_lifetime_bound)]
|
||||
pub struct ForbiddenLifetimeBound {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_non_lifetime_param)]
|
||||
pub struct ForbiddenNonLifetimeParam {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_too_many)]
|
||||
pub struct FnParamTooMany {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub max_num_args: usize,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_c_var_args_only)]
|
||||
pub struct FnParamCVarArgsOnly {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_c_var_args_not_last)]
|
||||
pub struct FnParamCVarArgsNotLast {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_doc_comment)]
|
||||
pub struct FnParamDocComment {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_forbidden_attr)]
|
||||
pub struct FnParamForbiddenAttr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_forbidden_self)]
|
||||
#[note]
|
||||
pub struct FnParamForbiddenSelf {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_default)]
|
||||
pub struct ForbiddenDefault {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub def_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::assoc_const_without_body)]
|
||||
pub struct AssocConstWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::assoc_fn_without_body)]
|
||||
pub struct AssocFnWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::assoc_type_without_body)]
|
||||
pub struct AssocTypeWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <type>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::const_without_body)]
|
||||
pub struct ConstWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::static_without_body)]
|
||||
pub struct StaticWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::ty_alias_without_body)]
|
||||
pub struct TyAliasWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <type>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_without_body)]
|
||||
pub struct FnWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub extern_block_suggestion: Option<ExternBlockSuggestion>,
|
||||
}
|
||||
|
||||
pub struct ExternBlockSuggestion {
|
||||
pub start_span: Span,
|
||||
pub end_span: Span,
|
||||
pub abi: Option<Symbol>,
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for ExternBlockSuggestion {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
let start_suggestion = if let Some(abi) = self.abi {
|
||||
format!("extern \"{}\" {{", abi)
|
||||
} else {
|
||||
"extern {".to_owned()
|
||||
};
|
||||
let end_suggestion = " }".to_owned();
|
||||
|
||||
diag.multipart_suggestion(
|
||||
fluent::ast_passes::extern_block_suggestion,
|
||||
vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -2,17 +2,15 @@ use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
|
||||
use rustc_ast::{PatKind, RangeEnd, VariantData};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_errors::{struct_span_err, Applicability, StashKey};
|
||||
use rustc_feature::Features;
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_feature::{Features, GateIssue};
|
||||
use rustc_session::parse::{feature_err, feature_err_issue};
|
||||
use rustc_session::parse::{feature_err, feature_warn};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
macro_rules! gate_feature_fn {
|
||||
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
|
||||
let (visitor, has_feature, span, name, explain, help) =
|
||||
@ -20,9 +18,7 @@ macro_rules! gate_feature_fn {
|
||||
let has_feature: bool = has_feature(visitor.features);
|
||||
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
||||
if !has_feature && !span.allows_unstable($name) {
|
||||
feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
|
||||
.help(help)
|
||||
.emit();
|
||||
feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit();
|
||||
}
|
||||
}};
|
||||
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
|
||||
@ -31,8 +27,19 @@ macro_rules! gate_feature_fn {
|
||||
let has_feature: bool = has_feature(visitor.features);
|
||||
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
||||
if !has_feature && !span.allows_unstable($name) {
|
||||
feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
|
||||
.emit();
|
||||
feature_err(&visitor.sess.parse_sess, name, span, explain).emit();
|
||||
}
|
||||
}};
|
||||
(future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
|
||||
let (visitor, has_feature, span, name, explain) =
|
||||
(&*$visitor, $has_feature, $span, $name, $explain);
|
||||
let has_feature: bool = has_feature(visitor.features);
|
||||
debug!(
|
||||
"gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)",
|
||||
name, span, has_feature
|
||||
);
|
||||
if !has_feature && !span.allows_unstable($name) {
|
||||
feature_warn(&visitor.sess.parse_sess, name, span, explain);
|
||||
}
|
||||
}};
|
||||
}
|
||||
@ -44,6 +51,9 @@ macro_rules! gate_feature_post {
|
||||
($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
|
||||
gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
|
||||
};
|
||||
(future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
|
||||
gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) {
|
||||
@ -330,25 +340,6 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_gat(&self, generics: &ast::Generics, span: Span) {
|
||||
if !generics.params.is_empty() {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
generic_associated_types,
|
||||
span,
|
||||
"generic associated types are unstable"
|
||||
);
|
||||
}
|
||||
if !generics.where_clause.predicates.is_empty() {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
generic_associated_types,
|
||||
span,
|
||||
"where clauses on associated types are unstable"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
|
||||
fn check_impl_trait(&self, ty: &ast::Ty) {
|
||||
struct ImplTraitVisitor<'a> {
|
||||
@ -417,6 +408,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
|| attr.has_name(sym::stable)
|
||||
|| attr.has_name(sym::rustc_const_unstable)
|
||||
|| attr.has_name(sym::rustc_const_stable)
|
||||
|| attr.has_name(sym::rustc_default_body_unstable)
|
||||
{
|
||||
struct_span_err!(
|
||||
self.sess,
|
||||
@ -562,6 +554,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
ast::TyKind::Never => {
|
||||
gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
|
||||
}
|
||||
ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::DynStar, ..) => {
|
||||
gate_feature_post!(&self, dyn_star, ty.span, "dyn* trait objects are unstable");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_ty(self, ty)
|
||||
@ -587,11 +582,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
{
|
||||
// When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
|
||||
// ascription error, but the likely intention was to write a `let` statement. (#78907).
|
||||
feature_err_issue(
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::type_ascription,
|
||||
lhs.span,
|
||||
GateIssue::Language,
|
||||
"type ascription is experimental",
|
||||
).span_suggestion_verbose(
|
||||
lhs.span.shrink_to_lo(),
|
||||
@ -614,28 +608,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Type(..) => {
|
||||
// To avoid noise about type ascription in common syntax errors, only emit if it
|
||||
// is the *only* error.
|
||||
if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
|
||||
// To avoid noise about type ascription in common syntax errors,
|
||||
// only emit if it is the *only* error.
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
type_ascription,
|
||||
e.span,
|
||||
"type ascription is experimental"
|
||||
);
|
||||
} else {
|
||||
// And if it isn't, cancel the early-pass warning.
|
||||
self.sess
|
||||
.parse_sess
|
||||
.span_diagnostic
|
||||
.steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
|
||||
.map(|err| err.cancel());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::TryBlock(_) => {
|
||||
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||
}
|
||||
ast::ExprKind::Block(_, Some(label)) => {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
label_break_value,
|
||||
label.ident.span,
|
||||
"labels on blocks are unstable"
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_expr(self, e)
|
||||
@ -690,7 +683,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
|
||||
}
|
||||
|
||||
visit::walk_fn(self, fn_kind, span)
|
||||
visit::walk_fn(self, fn_kind)
|
||||
}
|
||||
|
||||
fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
|
||||
@ -708,7 +701,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
|
||||
let is_fn = match i.kind {
|
||||
ast::AssocItemKind::Fn(_) => true,
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => {
|
||||
ast::AssocItemKind::TyAlias(box ast::TyAlias { ref ty, .. }) => {
|
||||
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
@ -720,7 +713,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
if let Some(ty) = ty {
|
||||
self.check_impl_trait(ty);
|
||||
}
|
||||
self.check_gat(generics, i.span);
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
@ -789,14 +781,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
|
||||
// All uses of `gate_all!` below this point were added in #65742,
|
||||
// and subsequently disabled (with the non-early gating readded).
|
||||
// We emit an early future-incompatible warning for these.
|
||||
// New syntax gates should go above here to get a hard error gate.
|
||||
macro_rules! gate_all {
|
||||
($gate:ident, $msg:literal) => {
|
||||
// FIXME(eddyb) do something more useful than always
|
||||
// disabling these uses of early feature-gatings.
|
||||
if false {
|
||||
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
|
||||
gate_feature_post!(&visitor, $gate, *span, $msg);
|
||||
}
|
||||
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
|
||||
gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -807,13 +797,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
gate_all!(box_patterns, "box pattern syntax is experimental");
|
||||
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
|
||||
gate_all!(try_blocks, "`try` blocks are unstable");
|
||||
gate_all!(label_break_value, "labels on blocks are unstable");
|
||||
gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
|
||||
// To avoid noise about type ascription in common syntax errors,
|
||||
// only emit if it is the *only* error. (Also check it last.)
|
||||
if sess.parse_sess.span_diagnostic.err_count() == 0 {
|
||||
gate_all!(type_ascription, "type ascription is experimental");
|
||||
}
|
||||
gate_all!(type_ascription, "type ascription is experimental");
|
||||
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
}
|
||||
|
||||
@ -9,10 +9,14 @@
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![cfg_attr(bootstrap, feature(let_else))]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
pub mod ast_validation;
|
||||
mod errors;
|
||||
pub mod feature_gate;
|
||||
pub mod node_count;
|
||||
pub mod show_span;
|
||||
|
||||
@ -63,9 +63,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
||||
self.count += 1;
|
||||
walk_generics(self, g)
|
||||
}
|
||||
fn visit_fn(&mut self, fk: visit::FnKind<'_>, s: Span, _: NodeId) {
|
||||
fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) {
|
||||
self.count += 1;
|
||||
walk_fn(self, fk, s)
|
||||
walk_fn(self, fk)
|
||||
}
|
||||
fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) {
|
||||
self.count += 1;
|
||||
@ -79,9 +79,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
||||
self.count += 1;
|
||||
walk_param_bound(self, bounds)
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) {
|
||||
fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) {
|
||||
self.count += 1;
|
||||
walk_poly_trait_ref(self, t, m)
|
||||
walk_poly_trait_ref(self, t)
|
||||
}
|
||||
fn visit_variant_data(&mut self, s: &VariantData) {
|
||||
self.count += 1;
|
||||
@ -91,15 +91,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
||||
self.count += 1;
|
||||
walk_field_def(self, s)
|
||||
}
|
||||
fn visit_enum_def(
|
||||
&mut self,
|
||||
enum_definition: &EnumDef,
|
||||
generics: &Generics,
|
||||
item_id: NodeId,
|
||||
_: Span,
|
||||
) {
|
||||
fn visit_enum_def(&mut self, enum_definition: &EnumDef) {
|
||||
self.count += 1;
|
||||
walk_enum_def(self, enum_definition, generics, item_id)
|
||||
walk_enum_def(self, enum_definition)
|
||||
}
|
||||
fn visit_variant(&mut self, v: &Variant) {
|
||||
self.count += 1;
|
||||
@ -121,9 +115,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
||||
self.count += 1;
|
||||
walk_use_tree(self, use_tree, id)
|
||||
}
|
||||
fn visit_generic_args(&mut self, path_span: Span, generic_args: &GenericArgs) {
|
||||
fn visit_generic_args(&mut self, generic_args: &GenericArgs) {
|
||||
self.count += 1;
|
||||
walk_generic_args(self, path_span, generic_args)
|
||||
walk_generic_args(self, generic_args)
|
||||
}
|
||||
fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
|
||||
self.count += 1;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(with_negative_coherence)]
|
||||
|
||||
@ -11,8 +11,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
|
||||
use rustc_ast::util::parser;
|
||||
use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
|
||||
use rustc_ast::{attr, Term};
|
||||
use rustc_ast::{self as ast, BlockCheckMode, Mutability, PatKind, RangeEnd, RangeSyntax};
|
||||
use rustc_ast::{attr, BindingAnnotation, ByRef, Term};
|
||||
use rustc_ast::{GenericArg, MacArgs, MacArgsEq};
|
||||
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
|
||||
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
|
||||
@ -22,6 +22,7 @@ use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
|
||||
use rustc_span::{BytePos, FileName, Span};
|
||||
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub use self::delimited::IterDelimited;
|
||||
@ -107,6 +108,7 @@ pub fn print_crate<'a>(
|
||||
ann: &'a dyn PpAnn,
|
||||
is_expanded: bool,
|
||||
edition: Edition,
|
||||
g: &AttrIdGenerator,
|
||||
) -> String {
|
||||
let mut s =
|
||||
State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
|
||||
@ -120,7 +122,7 @@ pub fn print_crate<'a>(
|
||||
// `#![feature(prelude_import)]`
|
||||
let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
|
||||
let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
|
||||
let fake_attr = attr::mk_attr_inner(list);
|
||||
let fake_attr = attr::mk_attr_inner(g, list);
|
||||
s.print_attribute(&fake_attr);
|
||||
|
||||
// Currently, in Rust 2018 we don't have `extern crate std;` at the crate
|
||||
@ -128,7 +130,7 @@ pub fn print_crate<'a>(
|
||||
if edition == Edition::Edition2015 {
|
||||
// `#![no_std]`
|
||||
let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
|
||||
let fake_attr = attr::mk_attr_inner(no_std_meta);
|
||||
let fake_attr = attr::mk_attr_inner(g, no_std_meta);
|
||||
s.print_attribute(&fake_attr);
|
||||
}
|
||||
}
|
||||
@ -372,7 +374,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
|
||||
fn print_literal(&mut self, lit: &ast::Lit) {
|
||||
self.maybe_print_comment(lit.span.lo());
|
||||
self.word(lit.token.to_string())
|
||||
self.word(lit.token_lit.to_string())
|
||||
}
|
||||
|
||||
fn print_string(&mut self, st: &str, style: ast::StrStyle) {
|
||||
@ -442,12 +444,12 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
}
|
||||
self.maybe_print_comment(attr.span.lo());
|
||||
match attr.kind {
|
||||
ast::AttrKind::Normal(ref item, _) => {
|
||||
ast::AttrKind::Normal(ref normal) => {
|
||||
match attr.style {
|
||||
ast::AttrStyle::Inner => self.word("#!["),
|
||||
ast::AttrStyle::Outer => self.word("#["),
|
||||
}
|
||||
self.print_attr_item(&item, attr.span);
|
||||
self.print_attr_item(&normal.item, attr.span);
|
||||
self.word("]");
|
||||
}
|
||||
ast::AttrKind::DocComment(comment_kind, data) => {
|
||||
@ -1399,16 +1401,12 @@ impl<'a> State<'a> {
|
||||
is that it doesn't matter */
|
||||
match pat.kind {
|
||||
PatKind::Wild => self.word("_"),
|
||||
PatKind::Ident(binding_mode, ident, ref sub) => {
|
||||
match binding_mode {
|
||||
ast::BindingMode::ByRef(mutbl) => {
|
||||
self.word_nbsp("ref");
|
||||
self.print_mutability(mutbl, false);
|
||||
}
|
||||
ast::BindingMode::ByValue(ast::Mutability::Not) => {}
|
||||
ast::BindingMode::ByValue(ast::Mutability::Mut) => {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, ref sub) => {
|
||||
if by_ref == ByRef::Yes {
|
||||
self.word_nbsp("ref");
|
||||
}
|
||||
if mutbl == Mutability::Mut {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
self.print_ident(ident);
|
||||
if let Some(ref p) = *sub {
|
||||
@ -1487,12 +1485,10 @@ impl<'a> State<'a> {
|
||||
}
|
||||
PatKind::Ref(ref inner, mutbl) => {
|
||||
self.word("&");
|
||||
if mutbl == ast::Mutability::Mut {
|
||||
if mutbl == Mutability::Mut {
|
||||
self.word("mut ");
|
||||
}
|
||||
if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) =
|
||||
inner.kind
|
||||
{
|
||||
if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind {
|
||||
self.popen();
|
||||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
|
||||
@ -218,6 +218,8 @@ impl<'a> State<'a> {
|
||||
ast::ItemKind::GlobalAsm(ref asm) => {
|
||||
self.head(visibility_qualified(&item.vis, "global_asm!"));
|
||||
self.print_inline_asm(asm);
|
||||
self.word(";");
|
||||
self.end();
|
||||
self.end();
|
||||
}
|
||||
ast::ItemKind::TyAlias(box ast::TyAlias {
|
||||
@ -412,9 +414,9 @@ impl<'a> State<'a> {
|
||||
pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) {
|
||||
match vis.kind {
|
||||
ast::VisibilityKind::Public => self.word_nbsp("pub"),
|
||||
ast::VisibilityKind::Restricted { ref path, .. } => {
|
||||
ast::VisibilityKind::Restricted { ref path, id: _, shorthand } => {
|
||||
let path = Self::to_string(|s| s.print_path(path, false, 0));
|
||||
if path == "crate" || path == "self" || path == "super" {
|
||||
if shorthand && (path == "crate" || path == "self" || path == "super") {
|
||||
self.word_nbsp(format!("pub({})", path))
|
||||
} else {
|
||||
self.word_nbsp(format!("pub(in {})", path))
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
@ -14,6 +13,20 @@ use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{symbol::sym, symbol::Symbol, Span};
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||
|
||||
/// The version placeholder that recently stabilized features contain inside the
|
||||
/// `since` field of the `#[stable]` attribute.
|
||||
///
|
||||
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
|
||||
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||
|
||||
pub fn rust_version_symbol() -> Symbol {
|
||||
let version = option_env!("CFG_VERSION").unwrap_or("<current>");
|
||||
let version = version.split(' ').next().unwrap();
|
||||
Symbol::intern(&version)
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
||||
attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
|
||||
}
|
||||
@ -25,46 +38,43 @@ enum AttrError {
|
||||
NonIdentFeature,
|
||||
MissingFeature,
|
||||
MultipleStabilityLevels,
|
||||
UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
|
||||
UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool),
|
||||
}
|
||||
|
||||
pub(crate) enum UnsupportedLiteralReason {
|
||||
Generic,
|
||||
CfgString,
|
||||
DeprecatedString,
|
||||
DeprecatedKvPair,
|
||||
}
|
||||
|
||||
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
|
||||
let diag = &sess.span_diagnostic;
|
||||
match error {
|
||||
AttrError::MultipleItem(item) => {
|
||||
struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit();
|
||||
sess.emit_err(session_diagnostics::MultipleItem { span, item });
|
||||
}
|
||||
AttrError::UnknownMetaItem(item, expected) => {
|
||||
let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
|
||||
struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item)
|
||||
.span_label(span, format!("expected one of {}", expected.join(", ")))
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected });
|
||||
}
|
||||
AttrError::MissingSince => {
|
||||
struct_span_err!(diag, span, E0542, "missing 'since'").emit();
|
||||
sess.emit_err(session_diagnostics::MissingSince { span });
|
||||
}
|
||||
AttrError::NonIdentFeature => {
|
||||
struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit();
|
||||
sess.emit_err(session_diagnostics::NonIdentFeature { span });
|
||||
}
|
||||
AttrError::MissingFeature => {
|
||||
struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
|
||||
sess.emit_err(session_diagnostics::MissingFeature { span });
|
||||
}
|
||||
AttrError::MultipleStabilityLevels => {
|
||||
struct_span_err!(diag, span, E0544, "multiple stability levels").emit();
|
||||
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
|
||||
}
|
||||
AttrError::UnsupportedLiteral(msg, is_bytestr) => {
|
||||
let mut err = struct_span_err!(diag, span, E0565, "{}", msg);
|
||||
if is_bytestr {
|
||||
if let Ok(lint_str) = sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider removing the prefix",
|
||||
&lint_str[1..],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
AttrError::UnsupportedLiteral(reason, is_bytestr) => {
|
||||
sess.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span,
|
||||
reason,
|
||||
is_bytestr,
|
||||
start_point_span: sess.source_map().start_point(span),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,6 +141,14 @@ impl ConstStability {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the `#[rustc_default_body_unstable]` attribute.
|
||||
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct DefaultBodyStability {
|
||||
pub level: StabilityLevel,
|
||||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
/// The available stability levels.
|
||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
@ -214,7 +232,8 @@ pub fn find_stability(
|
||||
sess: &Session,
|
||||
attrs: &[Attribute],
|
||||
item_sp: Span,
|
||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) {
|
||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
|
||||
{
|
||||
find_stability_generic(sess, attrs.iter(), item_sp)
|
||||
}
|
||||
|
||||
@ -222,7 +241,7 @@ fn find_stability_generic<'a, I>(
|
||||
sess: &Session,
|
||||
attrs_iter: I,
|
||||
item_sp: Span,
|
||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
|
||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
|
||||
where
|
||||
I: Iterator<Item = &'a Attribute>,
|
||||
{
|
||||
@ -230,11 +249,10 @@ where
|
||||
|
||||
let mut stab: Option<(Stability, Span)> = None;
|
||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
|
||||
let mut promotable = false;
|
||||
let mut allowed_through_unstable_modules = false;
|
||||
|
||||
let diagnostic = &sess.parse_sess.span_diagnostic;
|
||||
|
||||
'outer: for attr in attrs_iter {
|
||||
if ![
|
||||
sym::rustc_const_unstable,
|
||||
@ -243,6 +261,7 @@ where
|
||||
sym::stable,
|
||||
sym::rustc_promotable,
|
||||
sym::rustc_allowed_through_unstable_modules,
|
||||
sym::rustc_default_body_unstable,
|
||||
]
|
||||
.iter()
|
||||
.any(|&s| attr.has_name(s))
|
||||
@ -273,14 +292,14 @@ where
|
||||
*item = Some(v);
|
||||
true
|
||||
} else {
|
||||
struct_span_err!(diagnostic, meta.span, E0539, "incorrect meta item").emit();
|
||||
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let meta_name = meta.name_or_empty();
|
||||
match meta_name {
|
||||
sym::rustc_const_unstable | sym::unstable => {
|
||||
sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
|
||||
if meta_name == sym::unstable && stab.is_some() {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
@ -295,6 +314,13 @@ where
|
||||
AttrError::MultipleStabilityLevels,
|
||||
);
|
||||
break;
|
||||
} else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
attr.span,
|
||||
AttrError::MultipleStabilityLevels,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
let mut feature = None;
|
||||
@ -308,7 +334,7 @@ where
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
meta.span(),
|
||||
AttrError::UnsupportedLiteral("unsupported literal", false),
|
||||
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
||||
);
|
||||
continue 'outer;
|
||||
};
|
||||
@ -332,39 +358,28 @@ where
|
||||
// is a name/value pair string literal.
|
||||
issue_num = match issue.unwrap().as_str() {
|
||||
"none" => None,
|
||||
issue => {
|
||||
let emit_diag = |msg: &str| {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
mi.span,
|
||||
E0545,
|
||||
"`issue` must be a non-zero numeric string \
|
||||
or \"none\"",
|
||||
)
|
||||
.span_label(mi.name_value_literal_span().unwrap(), msg)
|
||||
.emit();
|
||||
};
|
||||
match issue.parse() {
|
||||
Ok(0) => {
|
||||
emit_diag(
|
||||
"`issue` must not be \"0\", \
|
||||
use \"none\" instead",
|
||||
);
|
||||
continue 'outer;
|
||||
}
|
||||
Ok(num) => NonZeroU32::new(num),
|
||||
Err(err) => {
|
||||
emit_diag(&err.to_string());
|
||||
continue 'outer;
|
||||
}
|
||||
issue => match issue.parse::<NonZeroU32>() {
|
||||
Ok(num) => Some(num),
|
||||
Err(err) => {
|
||||
sess.emit_err(
|
||||
session_diagnostics::InvalidIssueString {
|
||||
span: mi.span,
|
||||
cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
|
||||
mi.name_value_literal_span().unwrap(),
|
||||
err.kind(),
|
||||
),
|
||||
},
|
||||
);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
sym::soft => {
|
||||
if !mi.is_word() {
|
||||
let msg = "`soft` should not have any arguments";
|
||||
sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
|
||||
sess.emit_err(session_diagnostics::SoftNoArgs {
|
||||
span: mi.span,
|
||||
});
|
||||
}
|
||||
is_soft = true;
|
||||
}
|
||||
@ -405,11 +420,16 @@ where
|
||||
};
|
||||
if sym::unstable == meta_name {
|
||||
stab = Some((Stability { level, feature }, attr.span));
|
||||
} else {
|
||||
} else if sym::rustc_const_unstable == meta_name {
|
||||
const_stab = Some((
|
||||
ConstStability { level, feature, promotable: false },
|
||||
attr.span,
|
||||
));
|
||||
} else if sym::rustc_default_body_unstable == meta_name {
|
||||
body_stab =
|
||||
Some((DefaultBodyStability { level, feature }, attr.span));
|
||||
} else {
|
||||
unreachable!("Unknown stability attribute {meta_name}");
|
||||
}
|
||||
}
|
||||
(None, _, _) => {
|
||||
@ -417,8 +437,7 @@ where
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(diagnostic, attr.span, E0547, "missing 'issue'")
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -471,13 +490,20 @@ where
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
lit.span,
|
||||
AttrError::UnsupportedLiteral("unsupported literal", false),
|
||||
AttrError::UnsupportedLiteral(
|
||||
UnsupportedLiteralReason::Generic,
|
||||
false,
|
||||
),
|
||||
);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
||||
since = Some(rust_version_symbol());
|
||||
}
|
||||
|
||||
match (feature, since) {
|
||||
(Some(feature), Some(since)) => {
|
||||
let level = Stable { since, allowed_through_unstable_modules: false };
|
||||
@ -510,14 +536,7 @@ where
|
||||
if let Some((ref mut stab, _)) = const_stab {
|
||||
stab.promotable = promotable;
|
||||
} else {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item_sp,
|
||||
E0717,
|
||||
"`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \
|
||||
or a `rustc_const_stable` attribute"
|
||||
)
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp });
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,17 +551,11 @@ where
|
||||
{
|
||||
*allowed_through_unstable_modules = true;
|
||||
} else {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item_sp,
|
||||
E0789,
|
||||
"`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute"
|
||||
)
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
|
||||
}
|
||||
}
|
||||
|
||||
(stab, const_stab)
|
||||
(stab, const_stab, body_stab)
|
||||
}
|
||||
|
||||
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
||||
@ -652,25 +665,18 @@ pub fn eval_condition(
|
||||
NestedMetaItem::Literal(Lit { span, .. })
|
||||
| NestedMetaItem::MetaItem(MetaItem { span, .. }),
|
||||
] => {
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(*span, "expected a version literal")
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
|
||||
return false;
|
||||
}
|
||||
[..] => {
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(cfg.span, "expected single version literal")
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
|
||||
span: cfg.span,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let Some(min_version) = parse_version(min_version.as_str(), false) else {
|
||||
sess.span_diagnostic
|
||||
.struct_span_warn(
|
||||
*span,
|
||||
"unknown version literal format, assuming it refers to a future version",
|
||||
)
|
||||
.emit();
|
||||
sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
|
||||
return false;
|
||||
};
|
||||
let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
|
||||
@ -688,7 +694,7 @@ pub fn eval_condition(
|
||||
handle_errors(
|
||||
sess,
|
||||
mi.span(),
|
||||
AttrError::UnsupportedLiteral("unsupported literal", false),
|
||||
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@ -713,13 +719,9 @@ pub fn eval_condition(
|
||||
}),
|
||||
sym::not => {
|
||||
if mis.len() != 1 {
|
||||
struct_span_err!(
|
||||
sess.span_diagnostic,
|
||||
cfg.span,
|
||||
E0536,
|
||||
"expected 1 cfg-pattern"
|
||||
)
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::ExpectedOneCfgPattern {
|
||||
span: cfg.span,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -745,21 +747,16 @@ pub fn eval_condition(
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
sess.span_diagnostic,
|
||||
cfg.span,
|
||||
E0537,
|
||||
"invalid predicate `{}`",
|
||||
pprust::path_to_string(&cfg.path)
|
||||
)
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::InvalidPredicate {
|
||||
span: cfg.span,
|
||||
predicate: pprust::path_to_string(&cfg.path),
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
|
||||
sess.span_diagnostic
|
||||
.span_err(cfg.path.span, "`cfg` predicate key must be an identifier");
|
||||
sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
|
||||
true
|
||||
}
|
||||
MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => {
|
||||
@ -767,7 +764,7 @@ pub fn eval_condition(
|
||||
sess,
|
||||
lit.span,
|
||||
AttrError::UnsupportedLiteral(
|
||||
"literal in `cfg` predicate value must be a string",
|
||||
UnsupportedLiteralReason::CfgString,
|
||||
lit.kind.is_bytestr(),
|
||||
),
|
||||
);
|
||||
@ -811,7 +808,6 @@ where
|
||||
I: Iterator<Item = &'a Attribute>,
|
||||
{
|
||||
let mut depr: Option<(Deprecation, Span)> = None;
|
||||
let diagnostic = &sess.parse_sess.span_diagnostic;
|
||||
let is_rustc = sess.features_untracked().staged_api;
|
||||
|
||||
'outer: for attr in attrs_iter {
|
||||
@ -847,14 +843,14 @@ where
|
||||
&sess.parse_sess,
|
||||
lit.span,
|
||||
AttrError::UnsupportedLiteral(
|
||||
"literal in `deprecated` \
|
||||
value must be a string",
|
||||
UnsupportedLiteralReason::DeprecatedString,
|
||||
lit.kind.is_bytestr(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
struct_span_err!(diagnostic, meta.span, E0551, "incorrect meta item")
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::IncorrectMetaItem2 {
|
||||
span: meta.span,
|
||||
});
|
||||
}
|
||||
|
||||
false
|
||||
@ -876,14 +872,11 @@ where
|
||||
}
|
||||
sym::suggestion => {
|
||||
if !sess.features_untracked().deprecated_suggestion {
|
||||
let mut diag = sess.struct_span_err(
|
||||
mi.span,
|
||||
"suggestions on deprecated items are unstable",
|
||||
);
|
||||
if sess.is_nightly_build() {
|
||||
diag.help("add `#![feature(deprecated_suggestion)]` to the crate root");
|
||||
}
|
||||
diag.note("see #94785 for more details").emit();
|
||||
sess.emit_err(session_diagnostics::DeprecatedItemSuggestion {
|
||||
span: mi.span,
|
||||
is_nightly: sess.is_nightly_build().then_some(()),
|
||||
details: (),
|
||||
});
|
||||
}
|
||||
|
||||
if !get(mi, &mut suggestion) {
|
||||
@ -911,7 +904,7 @@ where
|
||||
&sess.parse_sess,
|
||||
lit.span,
|
||||
AttrError::UnsupportedLiteral(
|
||||
"item in `deprecated` must be a key/value pair",
|
||||
UnsupportedLiteralReason::DeprecatedKvPair,
|
||||
false,
|
||||
),
|
||||
);
|
||||
@ -929,7 +922,7 @@ where
|
||||
}
|
||||
|
||||
if note.is_none() {
|
||||
struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit();
|
||||
sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -999,19 +992,9 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
sym::simd => Some(ReprSimd),
|
||||
sym::transparent => Some(ReprTransparent),
|
||||
sym::align => {
|
||||
let mut err = struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0589,
|
||||
"invalid `repr(align)` attribute: `align` needs an argument"
|
||||
);
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"supply an argument here",
|
||||
"align(...)",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
err.emit();
|
||||
sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg {
|
||||
span: item.span(),
|
||||
});
|
||||
recognised = true;
|
||||
None
|
||||
}
|
||||
@ -1040,109 +1023,64 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
|| int_type_of_word(name).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0552,
|
||||
"invalid representation hint: `{}` does not take a parenthesized argument list",
|
||||
name.to_ident_string(),
|
||||
).emit();
|
||||
sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
|
||||
span: item.span(),
|
||||
name: name.to_ident_string(),
|
||||
});
|
||||
}
|
||||
if let Some(literal_error) = literal_error {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0589,
|
||||
"invalid `repr({})` attribute: {}",
|
||||
name.to_ident_string(),
|
||||
literal_error
|
||||
)
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::InvalidReprGeneric {
|
||||
span: item.span(),
|
||||
repr_arg: name.to_ident_string(),
|
||||
error_part: literal_error,
|
||||
});
|
||||
}
|
||||
} else if let Some(meta_item) = item.meta_item() {
|
||||
if let MetaItemKind::NameValue(ref value) = meta_item.kind {
|
||||
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
|
||||
let name = meta_item.name_or_empty().to_ident_string();
|
||||
recognised = true;
|
||||
let mut err = struct_span_err!(
|
||||
diagnostic,
|
||||
item.span(),
|
||||
E0693,
|
||||
"incorrect `repr({})` attribute format",
|
||||
name,
|
||||
);
|
||||
match value.kind {
|
||||
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("{}({})", name, int),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
ast::LitKind::Str(s, _) => {
|
||||
err.span_suggestion(
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("{}({})", name, s),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
err.emit();
|
||||
} else {
|
||||
if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::C | sym::simd | sym::transparent
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0552,
|
||||
"invalid representation hint: `{}` does not take a value",
|
||||
meta_item.name_or_empty().to_ident_string(),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
} else if let MetaItemKind::List(_) = meta_item.kind {
|
||||
if meta_item.has_name(sym::align) {
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0693,
|
||||
"incorrect `repr(align)` attribute format: \
|
||||
`align` takes exactly one argument in parentheses"
|
||||
)
|
||||
.emit();
|
||||
} else if meta_item.has_name(sym::packed) {
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0552,
|
||||
"incorrect `repr(packed)` attribute format: \
|
||||
`packed` takes exactly one parenthesized argument, \
|
||||
or no parentheses at all"
|
||||
)
|
||||
.emit();
|
||||
sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
|
||||
span: item.span(),
|
||||
repr_arg: &name,
|
||||
cause: IncorrectReprFormatGenericCause::from_lit_kind(
|
||||
item.span(),
|
||||
&value.kind,
|
||||
&name,
|
||||
),
|
||||
});
|
||||
} else if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::C | sym::simd | sym::transparent
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
meta_item.span,
|
||||
E0552,
|
||||
"invalid representation hint: `{}` does not take a parenthesized argument list",
|
||||
meta_item.name_or_empty().to_ident_string(),
|
||||
).emit();
|
||||
sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
|
||||
span: meta_item.span,
|
||||
name: meta_item.name_or_empty().to_ident_string(),
|
||||
});
|
||||
}
|
||||
} else if let MetaItemKind::List(_) = meta_item.kind {
|
||||
if meta_item.has_name(sym::align) {
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
|
||||
span: meta_item.span,
|
||||
});
|
||||
} else if meta_item.has_name(sym::packed) {
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
|
||||
span: meta_item.span,
|
||||
});
|
||||
} else if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::C | sym::simd | sym::transparent
|
||||
) || int_type_of_word(meta_item.name_or_empty()).is_some()
|
||||
{
|
||||
recognised = true;
|
||||
sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
|
||||
span: meta_item.span,
|
||||
name: meta_item.name_or_empty().to_ident_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1239,10 +1177,10 @@ fn allow_unstable<'a>(
|
||||
let list = attrs
|
||||
.filter_map(move |attr| {
|
||||
attr.meta_item_list().or_else(|| {
|
||||
sess.diagnostic().span_err(
|
||||
attr.span,
|
||||
&format!("`{}` expects a list of feature names", symbol.to_ident_string()),
|
||||
);
|
||||
sess.emit_err(session_diagnostics::ExpectsFeatureList {
|
||||
span: attr.span,
|
||||
name: symbol.to_ident_string(),
|
||||
});
|
||||
None
|
||||
})
|
||||
})
|
||||
@ -1251,10 +1189,10 @@ fn allow_unstable<'a>(
|
||||
list.into_iter().filter_map(move |it| {
|
||||
let name = it.ident().map(|ident| ident.name);
|
||||
if name.is_none() {
|
||||
sess.diagnostic().span_err(
|
||||
it.span(),
|
||||
&format!("`{}` expects feature names", symbol.to_ident_string()),
|
||||
);
|
||||
sess.emit_err(session_diagnostics::ExpectsFeatures {
|
||||
span: it.span(),
|
||||
name: symbol.to_ident_string(),
|
||||
});
|
||||
}
|
||||
name
|
||||
})
|
||||
|
||||
@ -5,12 +5,15 @@
|
||||
//! to this crate.
|
||||
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![cfg_attr(bootstrap, feature(let_else))]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
||||
mod builtin;
|
||||
mod session_diagnostics;
|
||||
|
||||
pub use builtin::*;
|
||||
pub use IntType::*;
|
||||
|
||||
398
compiler/rustc_attr/src/session_diagnostics.rs
Normal file
398
compiler/rustc_attr/src/session_diagnostics.rs
Normal file
@ -0,0 +1,398 @@
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{
|
||||
error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler,
|
||||
};
|
||||
use rustc_macros::SessionDiagnostic;
|
||||
use rustc_session::SessionDiagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::UnsupportedLiteralReason;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::expected_one_cfg_pattern, code = "E0536")]
|
||||
pub(crate) struct ExpectedOneCfgPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::invalid_predicate, code = "E0537")]
|
||||
pub(crate) struct InvalidPredicate {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub predicate: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::multiple_item, code = "E0538")]
|
||||
pub(crate) struct MultipleItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub item: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::incorrect_meta_item, code = "E0539")]
|
||||
pub(crate) struct IncorrectMetaItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// Error code: E0541
|
||||
pub(crate) struct UnknownMetaItem<'a> {
|
||||
pub span: Span,
|
||||
pub item: String,
|
||||
pub expected: &'a [&'a str],
|
||||
}
|
||||
|
||||
// Manual implementation to be able to format `expected` items correctly.
|
||||
impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> {
|
||||
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
|
||||
let mut diag = handler.struct_span_err_with_code(
|
||||
self.span,
|
||||
fluent::attr::unknown_meta_item,
|
||||
error_code!(E0541),
|
||||
);
|
||||
diag.set_arg("item", self.item);
|
||||
diag.set_arg("expected", expected.join(", "));
|
||||
diag.span_label(self.span, fluent::attr::label);
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::missing_since, code = "E0542")]
|
||||
pub(crate) struct MissingSince {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::missing_note, code = "E0543")]
|
||||
pub(crate) struct MissingNote {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::multiple_stability_levels, code = "E0544")]
|
||||
pub(crate) struct MultipleStabilityLevels {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::invalid_issue_string, code = "E0545")]
|
||||
pub(crate) struct InvalidIssueString {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[subdiagnostic]
|
||||
pub cause: Option<InvalidIssueStringCause>,
|
||||
}
|
||||
|
||||
// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be
|
||||
// translatable.
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub(crate) enum InvalidIssueStringCause {
|
||||
#[label(attr::must_not_be_zero)]
|
||||
MustNotBeZero {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr::empty)]
|
||||
Empty {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr::invalid_digit)]
|
||||
InvalidDigit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr::pos_overflow)]
|
||||
PosOverflow {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr::neg_overflow)]
|
||||
NegOverflow {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
impl InvalidIssueStringCause {
|
||||
pub fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> {
|
||||
match kind {
|
||||
IntErrorKind::Empty => Some(Self::Empty { span }),
|
||||
IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }),
|
||||
IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }),
|
||||
IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }),
|
||||
IntErrorKind::Zero => Some(Self::MustNotBeZero { span }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::missing_feature, code = "E0546")]
|
||||
pub(crate) struct MissingFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::non_ident_feature, code = "E0546")]
|
||||
pub(crate) struct NonIdentFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::missing_issue, code = "E0547")]
|
||||
pub(crate) struct MissingIssue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider
|
||||
// changing this to `IncorrectMetaItem`. See #51489.
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::incorrect_meta_item, code = "E0551")]
|
||||
pub(crate) struct IncorrectMetaItem2 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
|
||||
// It is more similar to `IncorrectReprFormatGeneric`.
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
|
||||
pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")]
|
||||
pub(crate) struct InvalidReprHintNoParen {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::invalid_repr_hint_no_value, code = "E0552")]
|
||||
pub(crate) struct InvalidReprHintNoValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
// Error code: E0565
|
||||
pub(crate) struct UnsupportedLiteral {
|
||||
pub span: Span,
|
||||
pub reason: UnsupportedLiteralReason,
|
||||
pub is_bytestr: bool,
|
||||
pub start_point_span: Span,
|
||||
}
|
||||
|
||||
impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
|
||||
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let mut diag = handler.struct_span_err_with_code(
|
||||
self.span,
|
||||
match self.reason {
|
||||
UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
|
||||
UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
|
||||
UnsupportedLiteralReason::DeprecatedString => {
|
||||
fluent::attr::unsupported_literal_deprecated_string
|
||||
}
|
||||
UnsupportedLiteralReason::DeprecatedKvPair => {
|
||||
fluent::attr::unsupported_literal_deprecated_kv_pair
|
||||
}
|
||||
},
|
||||
error_code!(E0565),
|
||||
);
|
||||
if self.is_bytestr {
|
||||
diag.span_suggestion(
|
||||
self.start_point_span,
|
||||
fluent::attr::unsupported_literal_suggestion,
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::invalid_repr_align_need_arg, code = "E0589")]
|
||||
pub(crate) struct InvalidReprAlignNeedArg {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "align(...)", applicability = "has-placeholders")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::invalid_repr_generic, code = "E0589")]
|
||||
pub(crate) struct InvalidReprGeneric<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub repr_arg: String,
|
||||
pub error_part: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")]
|
||||
pub(crate) struct IncorrectReprFormatAlignOneArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::incorrect_repr_format_generic, code = "E0693")]
|
||||
pub(crate) struct IncorrectReprFormatGeneric<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub repr_arg: &'a str,
|
||||
|
||||
#[subdiagnostic]
|
||||
pub cause: Option<IncorrectReprFormatGenericCause<'a>>,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub(crate) enum IncorrectReprFormatGenericCause<'a> {
|
||||
#[suggestion(attr::suggestion, code = "{name}({int})", applicability = "machine-applicable")]
|
||||
Int {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
||||
#[skip_arg]
|
||||
name: &'a str,
|
||||
|
||||
#[skip_arg]
|
||||
int: u128,
|
||||
},
|
||||
|
||||
#[suggestion(
|
||||
attr::suggestion,
|
||||
code = "{name}({symbol})",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
Symbol {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
||||
#[skip_arg]
|
||||
name: &'a str,
|
||||
|
||||
#[skip_arg]
|
||||
symbol: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> IncorrectReprFormatGenericCause<'a> {
|
||||
pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option<Self> {
|
||||
match kind {
|
||||
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
||||
Some(Self::Int { span, name, int: *int })
|
||||
}
|
||||
ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::rustc_promotable_pairing, code = "E0717")]
|
||||
pub(crate) struct RustcPromotablePairing {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")]
|
||||
pub(crate) struct RustcAllowedUnstablePairing {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::cfg_predicate_identifier)]
|
||||
pub(crate) struct CfgPredicateIdentifier {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::deprecated_item_suggestion)]
|
||||
pub(crate) struct DeprecatedItemSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[help]
|
||||
pub is_nightly: Option<()>,
|
||||
|
||||
#[note]
|
||||
pub details: (),
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::expected_single_version_literal)]
|
||||
pub(crate) struct ExpectedSingleVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::expected_version_literal)]
|
||||
pub(crate) struct ExpectedVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::expects_feature_list)]
|
||||
pub(crate) struct ExpectsFeatureList {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::expects_features)]
|
||||
pub(crate) struct ExpectsFeatures {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::soft_no_args)]
|
||||
pub(crate) struct SoftNoArgs {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(attr::unknown_version_literal)]
|
||||
pub(crate) struct UnknownVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
@ -31,7 +31,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
|
||||
body,
|
||||
};
|
||||
|
||||
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||
cg.visit_basic_block_data(bb, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,10 +21,7 @@ pub(crate) struct OutlivesConstraintSet<'tcx> {
|
||||
|
||||
impl<'tcx> OutlivesConstraintSet<'tcx> {
|
||||
pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
|
||||
debug!(
|
||||
"OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
|
||||
constraint.sup, constraint.sub, constraint.locations
|
||||
);
|
||||
debug!("OutlivesConstraintSet::push({:?})", constraint);
|
||||
if constraint.sup == constraint.sub {
|
||||
// 'a: 'a is pretty uninteresting
|
||||
return;
|
||||
@ -73,7 +70,7 @@ impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct OutlivesConstraint<'tcx> {
|
||||
// NB. The ordering here is not significant for correctness, but
|
||||
// it is for convenience. Before we dump the constraints in the
|
||||
@ -105,8 +102,8 @@ impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
formatter,
|
||||
"({:?}: {:?}) due to {:?} ({:?})",
|
||||
self.sup, self.sub, self.locations, self.variance_info
|
||||
"({:?}: {:?}) due to {:?} ({:?}) ({:?})",
|
||||
self.sup, self.sub, self.locations, self.variance_info, self.category,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ struct OutOfScopePrecomputer<'a, 'tcx> {
|
||||
impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
|
||||
fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
|
||||
OutOfScopePrecomputer {
|
||||
visited: BitSet::new_empty(body.basic_blocks().len()),
|
||||
visited: BitSet::new_empty(body.basic_blocks.len()),
|
||||
visit_stack: vec![],
|
||||
body,
|
||||
regioncx,
|
||||
@ -391,7 +391,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||
| mir::StatementKind::Retag { .. }
|
||||
| mir::StatementKind::AscribeUserType(..)
|
||||
| mir::StatementKind::Coverage(..)
|
||||
| mir::StatementKind::CopyNonOverlapping(..)
|
||||
| mir::StatementKind::Intrinsic(..)
|
||||
| mir::StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,9 +484,7 @@ fn try_extract_error_from_region_constraints<'tcx>(
|
||||
};
|
||||
nice_error.try_report_from_nll().or_else(|| {
|
||||
if let SubregionOrigin::Subtype(trace) = cause {
|
||||
Some(
|
||||
infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
|
||||
)
|
||||
Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@ -258,7 +258,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
|
||||
// If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
|
||||
if is_loop_move & !in_pattern {
|
||||
// Same for if we're in a loop, see #101119.
|
||||
if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
|
||||
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
|
||||
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
|
||||
err.span_suggestion_verbose(
|
||||
@ -451,7 +452,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
fn suggest_borrow_fn_like(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
err: &mut Diagnostic,
|
||||
ty: Ty<'tcx>,
|
||||
move_sites: &[MoveSite],
|
||||
value_name: &str,
|
||||
@ -526,12 +527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
true
|
||||
}
|
||||
|
||||
fn suggest_adding_copy_bounds(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
|
||||
@ -1124,6 +1120,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// short a lifetime. (But sometimes it is more useful to report
|
||||
/// it as a more direct conflict between the execution of a
|
||||
/// `Drop::drop` with an aliasing borrow.)
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn report_borrowed_value_does_not_live_long_enough(
|
||||
&mut self,
|
||||
location: Location,
|
||||
@ -1131,13 +1128,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
place_span: (Place<'tcx>, Span),
|
||||
kind: Option<WriteKind>,
|
||||
) {
|
||||
debug!(
|
||||
"report_borrowed_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}\
|
||||
)",
|
||||
location, borrow, place_span, kind
|
||||
);
|
||||
|
||||
let drop_span = place_span.1;
|
||||
let root_place =
|
||||
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
|
||||
@ -1194,10 +1184,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
|
||||
let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
|
||||
|
||||
debug!(
|
||||
"report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
|
||||
place_desc, explanation
|
||||
);
|
||||
debug!(?place_desc, ?explanation);
|
||||
|
||||
let err = match (place_desc, explanation) {
|
||||
// If the outlives constraint comes from inside the closure,
|
||||
// for example:
|
||||
@ -1469,6 +1457,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
err
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn report_temporary_value_does_not_live_long_enough(
|
||||
&mut self,
|
||||
location: Location,
|
||||
@ -1478,13 +1467,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
proper_span: Span,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
debug!(
|
||||
"report_temporary_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}\
|
||||
)",
|
||||
location, borrow, drop_span, proper_span
|
||||
);
|
||||
|
||||
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
|
||||
explanation
|
||||
{
|
||||
|
||||
@ -15,7 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::{sym, DesugaringKind, Span};
|
||||
|
||||
use crate::region_infer::BlameConstraint;
|
||||
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
|
||||
use crate::{
|
||||
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
|
||||
WriteKind,
|
||||
@ -38,6 +38,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
|
||||
span: Span,
|
||||
region_name: RegionName,
|
||||
opt_place_desc: Option<String>,
|
||||
extra_info: Vec<ExtraConstraintInfo>,
|
||||
},
|
||||
Unexplained,
|
||||
}
|
||||
@ -243,6 +244,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
ref region_name,
|
||||
ref opt_place_desc,
|
||||
from_closure: _,
|
||||
ref extra_info,
|
||||
} => {
|
||||
region_name.highlight_region_name(err);
|
||||
|
||||
@ -268,18 +270,30 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
);
|
||||
};
|
||||
|
||||
for extra in extra_info {
|
||||
match extra {
|
||||
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
|
||||
err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
|
||||
|
||||
fn add_lifetime_bound_suggestion_to_diagnostic(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
category: &ConstraintCategory<'tcx>,
|
||||
span: Span,
|
||||
region_name: &RegionName,
|
||||
) {
|
||||
if !span.is_desugaring(DesugaringKind::OpaqueTy) {
|
||||
return;
|
||||
}
|
||||
if let ConstraintCategory::OpaqueType = category {
|
||||
let suggestable_name =
|
||||
if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
|
||||
@ -305,18 +319,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
borrow_region: RegionVid,
|
||||
outlived_region: RegionVid,
|
||||
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>) {
|
||||
let BlameConstraint { category, from_closure, cause, variance_info: _ } =
|
||||
self.regioncx.best_blame_constraint(
|
||||
&self.body,
|
||||
borrow_region,
|
||||
NllRegionVariableOrigin::FreeRegion,
|
||||
|r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
|
||||
);
|
||||
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
|
||||
let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
|
||||
borrow_region,
|
||||
NllRegionVariableOrigin::FreeRegion,
|
||||
|r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
|
||||
);
|
||||
let BlameConstraint { category, from_closure, cause, .. } = blame_constraint;
|
||||
|
||||
let outlived_fr_name = self.give_region_a_name(outlived_region);
|
||||
|
||||
(category, from_closure, cause.span, outlived_fr_name)
|
||||
(category, from_closure, cause.span, outlived_fr_name, extra_info)
|
||||
}
|
||||
|
||||
/// Returns structured explanation for *why* the borrow contains the
|
||||
@ -332,26 +345,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// - second half is the place being accessed
|
||||
///
|
||||
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn explain_why_borrow_contains_point(
|
||||
&self,
|
||||
location: Location,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
kind_place: Option<(WriteKind, Place<'tcx>)>,
|
||||
) -> BorrowExplanation<'tcx> {
|
||||
debug!(
|
||||
"explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
|
||||
location, borrow, kind_place
|
||||
);
|
||||
|
||||
let regioncx = &self.regioncx;
|
||||
let body: &Body<'_> = &self.body;
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let borrow_region_vid = borrow.region;
|
||||
debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid);
|
||||
debug!(?borrow_region_vid);
|
||||
|
||||
let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
|
||||
debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub);
|
||||
debug!(?region_sub);
|
||||
|
||||
match find_use::find(body, regioncx, tcx, region_sub, location) {
|
||||
Some(Cause::LiveVar(local, location)) => {
|
||||
@ -392,7 +401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
None => {
|
||||
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
|
||||
let (category, from_closure, span, region_name) =
|
||||
let (category, from_closure, span, region_name, extra_info) =
|
||||
self.free_region_constraint_info(borrow_region_vid, region);
|
||||
if let Some(region_name) = region_name {
|
||||
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
|
||||
@ -402,19 +411,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span,
|
||||
region_name,
|
||||
opt_place_desc,
|
||||
extra_info,
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
"explain_why_borrow_contains_point: \
|
||||
Could not generate a region name"
|
||||
);
|
||||
debug!("Could not generate a region name");
|
||||
BorrowExplanation::Unexplained
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
"explain_why_borrow_contains_point: \
|
||||
Could not generate an error region vid"
|
||||
);
|
||||
debug!("Could not generate an error region vid");
|
||||
BorrowExplanation::Unexplained
|
||||
}
|
||||
}
|
||||
@ -455,7 +459,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return outmost_back_edge;
|
||||
}
|
||||
|
||||
let block = &self.body.basic_blocks()[location.block];
|
||||
let block = &self.body.basic_blocks[location.block];
|
||||
|
||||
if location.statement_index < block.statements.len() {
|
||||
let successor = location.successor_within_block();
|
||||
@ -514,7 +518,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
if loop_head.dominates(from, &self.dominators) {
|
||||
let block = &self.body.basic_blocks()[from.block];
|
||||
let block = &self.body.basic_blocks[from.block];
|
||||
|
||||
if from.statement_index < block.statements.len() {
|
||||
let successor = from.successor_within_block();
|
||||
@ -564,7 +568,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span)
|
||||
| UseSpans::FnSelfUse { var_span: span, .. } => {
|
||||
let block = &self.body.basic_blocks()[location.block];
|
||||
let block = &self.body.basic_blocks[location.block];
|
||||
|
||||
let kind = if let Some(&Statement {
|
||||
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
|
||||
|
||||
@ -1086,14 +1086,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
),
|
||||
);
|
||||
}
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.span_suggestion_verbose(
|
||||
fn_call_span.shrink_to_lo(),
|
||||
"consider calling `.as_ref()` to borrow the type's contents",
|
||||
"as_ref().",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// Avoid pointing to the same function in multiple different
|
||||
// error messages.
|
||||
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
|
||||
@ -1102,6 +1094,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
|
||||
);
|
||||
}
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.span_label(
|
||||
var_span,
|
||||
"help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
|
||||
);
|
||||
}
|
||||
}
|
||||
// Other desugarings takes &self, which cannot cause a move
|
||||
_ => {}
|
||||
|
||||
@ -88,7 +88,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some(StatementKind::Assign(box (
|
||||
place,
|
||||
Rvalue::Use(Operand::Move(move_from)),
|
||||
))) = self.body.basic_blocks()[location.block]
|
||||
))) = self.body.basic_blocks[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
.map(|stmt| &stmt.kind)
|
||||
@ -360,7 +360,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
diag.span_label(upvar_span, "captured outer variable");
|
||||
diag.span_label(
|
||||
self.body.span,
|
||||
self.infcx.tcx.def_span(def_id),
|
||||
format!("captured by this `{closure_kind}` closure"),
|
||||
);
|
||||
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
use rustc_errors::{
|
||||
Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{
|
||||
hir::place::PlaceBase,
|
||||
mir::{
|
||||
self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo,
|
||||
LocalKind, Location,
|
||||
},
|
||||
mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
|
||||
};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
|
||||
use crate::diagnostics::BorrowedContentSource;
|
||||
use crate::MirBorrowckCtxt;
|
||||
use rustc_const_eval::util::collect_writes::FindAssignments;
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum AccessKind {
|
||||
@ -309,7 +309,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
&& !matches!(
|
||||
decl.local_info,
|
||||
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
|
||||
ImplicitSelfKind::MutRef
|
||||
hir::ImplicitSelfKind::MutRef
|
||||
))))
|
||||
)
|
||||
{
|
||||
@ -364,7 +364,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
|
||||
&& let hir::PatKind::Binding(
|
||||
hir::BindingAnnotation::Unannotated,
|
||||
hir::BindingAnnotation::NONE,
|
||||
_,
|
||||
upvar_ident,
|
||||
_,
|
||||
@ -614,6 +614,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
"trait `IndexMut` is required to modify indexed content, \
|
||||
but it is not implemented for `{ty}`",
|
||||
));
|
||||
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@ -627,6 +628,127 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
fn suggest_map_index_mut_alternatives(
|
||||
&self,
|
||||
ty: Ty<'_>,
|
||||
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||
span: Span,
|
||||
) {
|
||||
let Some(adt) = ty.ty_adt_def() else { return };
|
||||
let did = adt.did();
|
||||
if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
|
||||
|| self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
|
||||
{
|
||||
struct V<'a, 'b, 'tcx, G: EmissionGuarantee> {
|
||||
assign_span: Span,
|
||||
err: &'a mut DiagnosticBuilder<'b, G>,
|
||||
ty: Ty<'tcx>,
|
||||
suggested: bool,
|
||||
}
|
||||
impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> {
|
||||
fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) {
|
||||
hir::intravisit::walk_stmt(self, stmt);
|
||||
let expr = match stmt.kind {
|
||||
hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
|
||||
hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
|
||||
&& let hir::ExprKind::Index(val, index) = place.kind
|
||||
&& (expr.span == self.assign_span || place.span == self.assign_span)
|
||||
{
|
||||
// val[index] = rv;
|
||||
// ---------- place
|
||||
self.err.multipart_suggestions(
|
||||
&format!(
|
||||
"to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
|
||||
self.ty,
|
||||
),
|
||||
vec![
|
||||
vec![ // val.insert(index, rv);
|
||||
(
|
||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||
".insert(".to_string(),
|
||||
),
|
||||
(
|
||||
index.span.shrink_to_hi().with_hi(rv.span.lo()),
|
||||
", ".to_string(),
|
||||
),
|
||||
(rv.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
vec![ // val.get_mut(index).map(|v| { *v = rv; });
|
||||
(
|
||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||
".get_mut(".to_string(),
|
||||
),
|
||||
(
|
||||
index.span.shrink_to_hi().with_hi(place.span.hi()),
|
||||
").map(|val| { *val".to_string(),
|
||||
),
|
||||
(
|
||||
rv.span.shrink_to_hi(),
|
||||
"; })".to_string(),
|
||||
),
|
||||
],
|
||||
vec![ // let x = val.entry(index).or_insert(rv);
|
||||
(val.span.shrink_to_lo(), "let val = ".to_string()),
|
||||
(
|
||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||
".entry(".to_string(),
|
||||
),
|
||||
(
|
||||
index.span.shrink_to_hi().with_hi(rv.span.lo()),
|
||||
").or_insert(".to_string(),
|
||||
),
|
||||
(rv.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
].into_iter(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
self.suggested = true;
|
||||
} else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
|
||||
&& let hir::ExprKind::Index(val, index) = receiver.kind
|
||||
&& expr.span == self.assign_span
|
||||
{
|
||||
// val[index].path(args..);
|
||||
self.err.multipart_suggestion(
|
||||
&format!("to modify a `{}` use `.get_mut()`", self.ty),
|
||||
vec![
|
||||
(
|
||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||
".get_mut(".to_string(),
|
||||
),
|
||||
(
|
||||
index.span.shrink_to_hi().with_hi(receiver.span.hi()),
|
||||
").map(|val| val".to_string(),
|
||||
),
|
||||
(sp.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
self.suggested = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
let hir_map = self.infcx.tcx.hir();
|
||||
let def_id = self.body.source.def_id();
|
||||
let hir_id = hir_map.local_def_id_to_hir_id(def_id.as_local().unwrap());
|
||||
let node = hir_map.find(hir_id);
|
||||
let Some(hir::Node::Item(item)) = node else { return; };
|
||||
let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
|
||||
let body = self.infcx.tcx.hir().body(body_id);
|
||||
let mut v = V { assign_span: span, err, ty, suggested: false };
|
||||
v.visit_body(body);
|
||||
if !v.suggested {
|
||||
err.help(&format!(
|
||||
"to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// User cannot make signature of a trait mutable without changing the
|
||||
/// trait. So we find if this error belongs to a trait and if so we move
|
||||
/// suggestion to the trait or disable it if it is out of scope of this crate
|
||||
@ -786,11 +908,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
[
|
||||
Expr {
|
||||
kind:
|
||||
MethodCall(
|
||||
path_segment,
|
||||
_args,
|
||||
span,
|
||||
),
|
||||
MethodCall(path_segment, _, _, span),
|
||||
hir_id,
|
||||
..
|
||||
},
|
||||
@ -810,10 +928,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
_,
|
||||
) = hir_map.body(fn_body_id).value.kind
|
||||
{
|
||||
let opt_suggestions = path_segment
|
||||
.hir_id
|
||||
.map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
|
||||
.and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
|
||||
let opt_suggestions = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(path_segment.hir_id.owner)
|
||||
.type_dependent_def_id(*hir_id)
|
||||
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
|
||||
.map(|def_id| self.infcx.tcx.associated_items(def_id))
|
||||
.map(|assoc_items| {
|
||||
@ -851,6 +970,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
let hir = self.infcx.tcx.hir();
|
||||
let closure_id = self.mir_hir_id();
|
||||
let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
|
||||
let fn_call_id = hir.get_parent_node(closure_id);
|
||||
let node = hir.get(fn_call_id);
|
||||
let def_id = hir.enclosing_body_owner(fn_call_id);
|
||||
@ -902,7 +1022,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some(span) = arg {
|
||||
err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
|
||||
err.span_label(func.span, "expects `Fn` instead of `FnMut`");
|
||||
err.span_label(self.body.span, "in this closure");
|
||||
err.span_label(closure_span, "in this closure");
|
||||
look_at_return = false;
|
||||
}
|
||||
}
|
||||
@ -928,7 +1048,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
sig.decl.output.span(),
|
||||
"change this to return `FnMut` instead of `Fn`",
|
||||
);
|
||||
err.span_label(self.body.span, "in this closure");
|
||||
err.span_label(closure_span, "in this closure");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -952,7 +1072,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
|
||||
//
|
||||
// Deliberately fall into this case for all implicit self types,
|
||||
// so that we don't fall in to the next case with them.
|
||||
*kind == mir::ImplicitSelfKind::MutRef
|
||||
*kind == hir::ImplicitSelfKind::MutRef
|
||||
}
|
||||
_ if Some(kw::SelfLower) == local_name => {
|
||||
// Otherwise, check if the name is the `self` keyword - in which case
|
||||
|
||||
@ -6,7 +6,6 @@ use rustc_errors::Diagnostic;
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::BTreeMap;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::MirBorrowckCtxt;
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
@ -23,10 +25,13 @@ use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::borrowck_errors;
|
||||
use crate::session_diagnostics::GenericDoesNotLiveLongEnough;
|
||||
use crate::session_diagnostics::{
|
||||
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
|
||||
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
|
||||
};
|
||||
|
||||
use super::{OutlivesSuggestionBuilder, RegionName};
|
||||
use crate::region_infer::BlameConstraint;
|
||||
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
|
||||
use crate::{
|
||||
nll::ConstraintDescription,
|
||||
region_infer::{values::RegionElement, TypeTest},
|
||||
@ -229,7 +234,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
|
||||
let (_, cause) = self.regioncx.find_outlives_blame_span(
|
||||
&self.body,
|
||||
longer_fr,
|
||||
NllRegionVariableOrigin::Placeholder(placeholder),
|
||||
error_vid,
|
||||
@ -350,10 +354,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
) {
|
||||
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
||||
|
||||
let BlameConstraint { category, cause, variance_info, from_closure: _ } =
|
||||
self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
|
||||
let (blame_constraint, extra_info) =
|
||||
self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
|
||||
self.regioncx.provides_universal_region(r, fr, outlived_fr)
|
||||
});
|
||||
let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
|
||||
|
||||
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
|
||||
|
||||
@ -462,6 +467,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
for extra in extra_info {
|
||||
match extra {
|
||||
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
|
||||
diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.buffer_error(diag);
|
||||
}
|
||||
|
||||
@ -488,12 +501,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
|
||||
|
||||
let mut diag = self
|
||||
.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
|
||||
|
||||
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
if let ty::Opaque(def_id, _) = *output_ty.kind() {
|
||||
output_ty = self.infcx.tcx.type_of(def_id)
|
||||
@ -501,19 +508,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
debug!("report_fnmut_error: output_ty={:?}", output_ty);
|
||||
|
||||
let message = match output_ty.kind() {
|
||||
ty::Closure(_, _) => {
|
||||
"returns a closure that contains a reference to a captured variable, which then \
|
||||
escapes the closure body"
|
||||
}
|
||||
ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => {
|
||||
"returns an `async` block that contains a reference to a captured variable, which then \
|
||||
escapes the closure body"
|
||||
}
|
||||
_ => "returns a reference to a captured variable which escapes the closure body",
|
||||
let err = FnMutError {
|
||||
span: *span,
|
||||
ty_err: match output_ty.kind() {
|
||||
ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span },
|
||||
ty::Adt(def, _)
|
||||
if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) =>
|
||||
{
|
||||
FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
|
||||
}
|
||||
_ => FnMutReturnTypeErr::ReturnRef { span: *span },
|
||||
},
|
||||
};
|
||||
|
||||
diag.span_label(*span, message);
|
||||
let mut diag = self.infcx.tcx.sess.create_err(err);
|
||||
|
||||
if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
|
||||
let def_id = match self.regioncx.universal_regions().defining_ty {
|
||||
@ -532,20 +540,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
|
||||
let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
|
||||
let upvar_span = upvars_map.get(&def_hir).unwrap().span;
|
||||
diag.span_label(upvar_def_span, "variable defined here");
|
||||
diag.span_label(upvar_span, "variable captured here");
|
||||
diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
|
||||
diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
|
||||
diag.span_label(fr_span, "inferred to be a `FnMut` closure");
|
||||
diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
|
||||
}
|
||||
|
||||
diag.note(
|
||||
"`FnMut` closures only have access to their captured variables while they are \
|
||||
executing...",
|
||||
);
|
||||
diag.note("...therefore, they cannot allow references to captured variables to escape");
|
||||
self.suggest_move_on_borrowing_closure(&mut diag);
|
||||
|
||||
diag
|
||||
}
|
||||
@ -562,6 +566,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// LL | ref_obj(x)
|
||||
/// | ^^^^^^^^^^ `x` escapes the function body here
|
||||
/// ```
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn report_escaping_data_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
@ -680,42 +685,37 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
..
|
||||
} = errci;
|
||||
|
||||
let mut diag =
|
||||
self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
|
||||
|
||||
let (_, mir_def_name) =
|
||||
self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
|
||||
|
||||
let err = LifetimeOutliveErr { span: *span };
|
||||
let mut diag = self.infcx.tcx.sess.create_err(err);
|
||||
|
||||
let fr_name = self.give_region_a_name(*fr).unwrap();
|
||||
fr_name.highlight_region_name(&mut diag);
|
||||
let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
|
||||
outlived_fr_name.highlight_region_name(&mut diag);
|
||||
|
||||
match (category, outlived_fr_is_local, fr_is_local) {
|
||||
(ConstraintCategory::Return(_), true, _) => {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \
|
||||
data with lifetime `{fr_name}`",
|
||||
),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"{}requires that `{}` must outlive `{}`",
|
||||
category.description(),
|
||||
fr_name,
|
||||
outlived_fr_name,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
let err_category = match (category, outlived_fr_is_local, fr_is_local) {
|
||||
(ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn {
|
||||
span: *span,
|
||||
mir_def_name,
|
||||
outlived_fr_name,
|
||||
fr_name: &fr_name,
|
||||
},
|
||||
_ => LifetimeReturnCategoryErr::ShortReturn {
|
||||
span: *span,
|
||||
category_desc: category.description(),
|
||||
free_region_name: &fr_name,
|
||||
outlived_fr_name,
|
||||
},
|
||||
};
|
||||
|
||||
diag.subdiagnostic(err_category);
|
||||
|
||||
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
|
||||
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
|
||||
self.suggest_move_on_borrowing_closure(&mut diag);
|
||||
|
||||
diag
|
||||
}
|
||||
@ -783,7 +783,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
fn maybe_suggest_constrain_dyn_trait_impl(
|
||||
&self,
|
||||
diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
diag: &mut Diagnostic,
|
||||
f: Region<'tcx>,
|
||||
o: Region<'tcx>,
|
||||
category: &ConstraintCategory<'tcx>,
|
||||
@ -860,7 +860,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
ident.span,
|
||||
"calling this method introduces the `impl`'s 'static` requirement",
|
||||
);
|
||||
err.span_note(multi_span, "the used `impl` has a `'static` requirement");
|
||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"consider relaxing the implicit `'static` requirement",
|
||||
@ -901,4 +901,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
|
||||
}
|
||||
|
||||
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body_id = map.body_owned_by(self.mir_def_id());
|
||||
let expr = &map.body(body_id).value;
|
||||
let mut closure_span = None::<rustc_span::Span>;
|
||||
match expr.kind {
|
||||
hir::ExprKind::MethodCall(.., args, _) => {
|
||||
for arg in args {
|
||||
if let hir::ExprKind::Closure(hir::Closure {
|
||||
capture_clause: hir::CaptureBy::Ref,
|
||||
..
|
||||
}) = arg.kind
|
||||
{
|
||||
closure_span = Some(arg.span.shrink_to_lo());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Block(blk, _) => {
|
||||
if let Some(ref expr) = blk.expr {
|
||||
// only when the block is a closure
|
||||
if let hir::ExprKind::Closure(hir::Closure {
|
||||
capture_clause: hir::CaptureBy::Ref,
|
||||
..
|
||||
}) = expr.kind
|
||||
{
|
||||
closure_span = Some(expr.span.shrink_to_lo());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(closure_span) = closure_span {
|
||||
diag.span_suggestion_verbose(
|
||||
closure_span,
|
||||
"consider adding 'move' keyword before the nested closure",
|
||||
"move ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,7 +265,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
/// *user* has a name for. In that case, we'll be able to map
|
||||
/// `fr` to a `Region<'tcx>`, and that region will be one of
|
||||
/// named variants.
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
|
||||
let error_region = self.to_error_region(fr)?;
|
||||
|
||||
@ -357,11 +357,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
ty::BoundRegionKind::BrAnon(_) => None,
|
||||
},
|
||||
|
||||
ty::ReLateBound(..)
|
||||
| ty::ReVar(..)
|
||||
| ty::RePlaceholder(..)
|
||||
| ty::ReEmpty(_)
|
||||
| ty::ReErased => None,
|
||||
ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,7 +369,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
/// | fn foo(x: &u32) { .. }
|
||||
/// ------- fully elaborated type of `x` is `&'1 u32`
|
||||
/// ```
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn give_name_if_anonymous_region_appears_in_arguments(
|
||||
&self,
|
||||
fr: RegionVid,
|
||||
@ -662,7 +658,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
/// | let x = Some(&22);
|
||||
/// - fully elaborated type of `x` is `Option<&'1 u32>`
|
||||
/// ```
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
|
||||
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
|
||||
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
|
||||
@ -682,7 +678,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
/// must be a closure since, in a free fn, such an argument would
|
||||
/// have to either also appear in an argument (if using elision)
|
||||
/// or be early bound (named, not in argument).
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
@ -772,7 +768,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
|
||||
let hir = self.infcx.tcx.hir();
|
||||
|
||||
let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
|
||||
let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
|
||||
span_bug!(
|
||||
hir_ty.span,
|
||||
"lowered return type of async fn is not OpaqueDef: {:?}",
|
||||
@ -814,7 +810,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn give_name_if_anonymous_region_appears_in_yield_ty(
|
||||
&self,
|
||||
fr: RegionVid,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
|
||||
use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
|
||||
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
|
||||
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||
use rustc_middle::mir::{Statement, StatementKind};
|
||||
@ -63,23 +63,24 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
StatementKind::FakeRead(box (_, _)) => {
|
||||
// Only relevant for initialized/liveness/safety checks.
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
|
||||
self.consume_operand(location, op);
|
||||
}
|
||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
|
||||
ref src,
|
||||
ref dst,
|
||||
ref count,
|
||||
}) => {
|
||||
})) => {
|
||||
self.consume_operand(location, src);
|
||||
self.consume_operand(location, dst);
|
||||
self.consume_operand(location, count);
|
||||
}
|
||||
StatementKind::Nop
|
||||
// Only relevant for mir typeck
|
||||
StatementKind::AscribeUserType(..)
|
||||
// Doesn't have any language semantics
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::StorageLive(..) => {
|
||||
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
|
||||
// to borrow check.
|
||||
}
|
||||
// Does not actually affect borrowck
|
||||
| StatementKind::StorageLive(..) => {}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.access_place(
|
||||
location,
|
||||
@ -88,7 +89,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
LocalMutationIsAllowed::Yes,
|
||||
);
|
||||
}
|
||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||
StatementKind::Nop
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::SetDiscriminant { .. } => {
|
||||
bug!("Statement not allowed in this MIR phase")
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![cfg_attr(bootstrap, feature(let_else))]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
@ -19,15 +19,15 @@ extern crate tracing;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::ChunkedBitSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_middle::mir::{
|
||||
traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
|
||||
PlaceRef, VarDebugInfoContents,
|
||||
traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
|
||||
Place, PlaceElem, PlaceRef, VarDebugInfoContents,
|
||||
};
|
||||
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
|
||||
@ -51,6 +51,8 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveE
|
||||
use rustc_mir_dataflow::Analysis;
|
||||
use rustc_mir_dataflow::MoveDataParamEnv;
|
||||
|
||||
use crate::session_diagnostics::VarNeedNotMut;
|
||||
|
||||
use self::diagnostics::{AccessKind, RegionName};
|
||||
use self::location::LocationTable;
|
||||
use self::prefixes::PrefixSet;
|
||||
@ -425,17 +427,9 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||
continue;
|
||||
}
|
||||
|
||||
tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| {
|
||||
let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
|
||||
lint.build("variable does not need to be mutable")
|
||||
.span_suggestion_short(
|
||||
mut_span,
|
||||
"remove this `mut`",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
})
|
||||
let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
|
||||
|
||||
tcx.emit_spanned_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
|
||||
}
|
||||
|
||||
let tainted_by_errors = mbcx.emit_errors();
|
||||
@ -597,22 +591,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
..
|
||||
}) => {
|
||||
span_bug!(
|
||||
StatementKind::Intrinsic(box ref kind) => match kind {
|
||||
NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
|
||||
NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
|
||||
span,
|
||||
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
|
||||
)
|
||||
}
|
||||
StatementKind::Nop
|
||||
// Only relevant for mir typeck
|
||||
StatementKind::AscribeUserType(..)
|
||||
// Doesn't have any language semantics
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::StorageLive(..) => {
|
||||
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
|
||||
// to borrow check.
|
||||
}
|
||||
// Does not actually affect borrowck
|
||||
| StatementKind::StorageLive(..) => {}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.access_place(
|
||||
location,
|
||||
@ -622,7 +613,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||
StatementKind::Nop
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::SetDiscriminant { .. } => {
|
||||
bug!("Statement not allowed in this MIR phase")
|
||||
}
|
||||
}
|
||||
@ -982,6 +976,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, flow_state))]
|
||||
fn check_access_for_conflict(
|
||||
&mut self,
|
||||
location: Location,
|
||||
@ -990,11 +985,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
rw: ReadOrWrite,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})",
|
||||
location, place_span, sd, rw,
|
||||
);
|
||||
|
||||
let mut error_reported = false;
|
||||
let tcx = self.infcx.tcx;
|
||||
let body = self.body;
|
||||
@ -1458,13 +1448,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
/// Checks whether a borrow of this place is invalidated when the function
|
||||
/// exits
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn check_for_invalidation_at_exit(
|
||||
&mut self,
|
||||
location: Location,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
debug!("check_for_invalidation_at_exit({:?})", borrow);
|
||||
let place = borrow.borrowed_place;
|
||||
let mut root_place = PlaceRef { local: place.local, projection: &[] };
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ impl LocationTable {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block = body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
@ -86,8 +86,7 @@ impl LocationTable {
|
||||
let (block, &first_index) = self
|
||||
.statements_before_block
|
||||
.iter_enumerated()
|
||||
.filter(|(_, first_index)| **first_index <= point_index)
|
||||
.last()
|
||||
.rfind(|&(_, &first_index)| first_index <= point_index)
|
||||
.unwrap();
|
||||
|
||||
let statement_index = (point_index - first_index) / 2;
|
||||
|
||||
@ -389,8 +389,9 @@ pub(super) fn dump_annotation<'a, 'tcx>(
|
||||
// viewing the intraprocedural state, the -Zdump-mir output is
|
||||
// better.
|
||||
|
||||
let def_span = tcx.def_span(body.source.def_id());
|
||||
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
|
||||
let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements");
|
||||
let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "external requirements");
|
||||
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
||||
@ -409,7 +410,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
|
||||
|
||||
err
|
||||
} else {
|
||||
let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements");
|
||||
let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "no external requirements");
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
||||
err
|
||||
|
||||
@ -44,6 +44,7 @@ pub(crate) fn places_conflict<'tcx>(
|
||||
/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
|
||||
/// array indices, for example) should be interpreted - this depends on what the caller wants in
|
||||
/// order to make the conservative choice and preserve soundness.
|
||||
#[instrument(level = "debug", skip(tcx, body))]
|
||||
pub(super) fn borrow_conflicts_with_place<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
@ -53,11 +54,6 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
|
||||
access: AccessDepth,
|
||||
bias: PlaceConflictBias,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
|
||||
borrow_place, access_place, access, bias,
|
||||
);
|
||||
|
||||
// This Local/Local case is handled by the more general code below, but
|
||||
// it's so common that it's a speed win to check for it first.
|
||||
if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() {
|
||||
@ -140,10 +136,9 @@ fn place_components_conflict<'tcx>(
|
||||
for (i, (borrow_c, &access_c)) in
|
||||
iter::zip(borrow_place.projection, access_place.projection).enumerate()
|
||||
{
|
||||
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
|
||||
let borrow_proj_base = &borrow_place.projection[..i];
|
||||
debug!(?borrow_c, ?access_c);
|
||||
|
||||
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
|
||||
let borrow_proj_base = &borrow_place.projection[..i];
|
||||
|
||||
// Borrow and access path both have more components.
|
||||
//
|
||||
@ -180,7 +175,7 @@ fn place_components_conflict<'tcx>(
|
||||
// idea, at least for now, so just give up and
|
||||
// report a conflict. This is unsafe code anyway so
|
||||
// the user could always use raw pointers.
|
||||
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
|
||||
debug!("arbitrary -> conflict");
|
||||
return true;
|
||||
}
|
||||
Overlap::EqualOrDisjoint => {
|
||||
@ -189,7 +184,7 @@ fn place_components_conflict<'tcx>(
|
||||
Overlap::Disjoint => {
|
||||
// We have proven the borrow disjoint - further
|
||||
// projections will remain disjoint.
|
||||
debug!("borrow_conflicts_with_place: disjoint");
|
||||
debug!("disjoint");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> {
|
||||
/// adds a new lower bound to the SCC it is analyzing: so you wind up
|
||||
/// with `'R: 'O` where `'R` is the pick-region and `'O` is the
|
||||
/// minimal viable option.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub(crate) struct AppliedMemberConstraint {
|
||||
/// The SCC that was affected. (The "member region".)
|
||||
///
|
||||
@ -246,6 +245,11 @@ enum Trace<'tcx> {
|
||||
NotVisited,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ExtraConstraintInfo {
|
||||
PlaceholderFromPredicate(Span),
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Creates a new region inference context with a total of
|
||||
/// `num_region_variables` valid inference variables; the first N
|
||||
@ -591,13 +595,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// constraints were too strong, and if so, emit or propagate those errors.
|
||||
if infcx.tcx.sess.opts.unstable_opts.polonius {
|
||||
self.check_polonius_subset_errors(
|
||||
body,
|
||||
outlives_requirements.as_mut(),
|
||||
&mut errors_buffer,
|
||||
polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"),
|
||||
);
|
||||
} else {
|
||||
self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
}
|
||||
|
||||
if errors_buffer.is_empty() {
|
||||
@ -1139,7 +1142,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// include the CFG anyhow.
|
||||
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
|
||||
/// a result `'y`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
debug!(r = %self.region_value_str(r));
|
||||
|
||||
@ -1151,8 +1154,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
|
||||
}
|
||||
|
||||
debug!(?lub);
|
||||
|
||||
lub
|
||||
}
|
||||
|
||||
@ -1167,8 +1168,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Therefore, this method should only be used in diagnostic code,
|
||||
/// where displaying *some* named universal region is better than
|
||||
/// falling back to 'static.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
|
||||
debug!("{}", self.region_value_str(r));
|
||||
|
||||
// Find the smallest universal region that contains all other
|
||||
// universal regions within `region`.
|
||||
@ -1177,7 +1179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let static_r = self.universal_regions.fr_static;
|
||||
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
|
||||
let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
|
||||
debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub);
|
||||
debug!(?ur, ?lub, ?new_lub);
|
||||
// The upper bound of two non-static regions is static: this
|
||||
// means we know nothing about the relationship between these
|
||||
// two regions. Pick a 'better' one to use when constructing
|
||||
@ -1201,7 +1203,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub);
|
||||
debug!(?r, ?lub);
|
||||
|
||||
lub
|
||||
}
|
||||
@ -1332,15 +1334,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
|
||||
// Evaluate whether `sup_region: sub_region`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
|
||||
debug!(
|
||||
"eval_outlives: sup_region's value = {:?} universal={:?}",
|
||||
"sup_region's value = {:?} universal={:?}",
|
||||
self.region_value_str(sup_region),
|
||||
self.universal_regions.is_universal_region(sup_region),
|
||||
);
|
||||
debug!(
|
||||
"eval_outlives: sub_region's value = {:?} universal={:?}",
|
||||
"sub_region's value = {:?} universal={:?}",
|
||||
self.region_value_str(sub_region),
|
||||
self.universal_regions.is_universal_region(sub_region),
|
||||
);
|
||||
@ -1353,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// true if `'sup` outlives static.
|
||||
if !self.universe_compatible(sub_region_scc, sup_region_scc) {
|
||||
debug!(
|
||||
"eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
|
||||
"sub universe `{sub_region_scc:?}` is not nameable \
|
||||
by super `{sup_region_scc:?}`, promoting to static",
|
||||
);
|
||||
|
||||
@ -1374,9 +1376,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
});
|
||||
|
||||
if !universal_outlives {
|
||||
debug!(
|
||||
"eval_outlives: returning false because sub region contains a universal region not present in super"
|
||||
);
|
||||
debug!("sub region contains a universal region not present in super");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1385,15 +1385,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
if self.universal_regions.is_universal_region(sup_region) {
|
||||
// Micro-opt: universal regions contain all points.
|
||||
debug!(
|
||||
"eval_outlives: returning true because super is universal and hence contains all points"
|
||||
);
|
||||
debug!("super is universal and hence contains all points");
|
||||
return true;
|
||||
}
|
||||
|
||||
let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
|
||||
debug!("returning {} because of comparison between points in sup/sub", result);
|
||||
result
|
||||
debug!("comparison between points in sup/sub");
|
||||
|
||||
self.scc_values.contains_points(sup_region_scc, sub_region_scc)
|
||||
}
|
||||
|
||||
/// Once regions have been propagated, this method is used to see
|
||||
@ -1415,7 +1413,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// report them as errors.
|
||||
fn check_universal_regions(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
) {
|
||||
@ -1426,7 +1423,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// they did not grow too large, accumulating any requirements
|
||||
// for our caller into the `outlives_requirements` vector.
|
||||
self.check_universal_region(
|
||||
body,
|
||||
fr,
|
||||
&mut propagated_outlives_requirements,
|
||||
errors_buffer,
|
||||
@ -1467,7 +1463,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// report them as errors.
|
||||
fn check_polonius_subset_errors(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
polonius_output: Rc<PoloniusOutput>,
|
||||
@ -1514,7 +1509,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let propagated = self.try_propagate_universal_region_error(
|
||||
*longer_fr,
|
||||
*shorter_fr,
|
||||
body,
|
||||
&mut propagated_outlives_requirements,
|
||||
);
|
||||
if propagated == RegionRelationCheckResult::Error {
|
||||
@ -1554,13 +1548,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
///
|
||||
/// Things that are to be propagated are accumulated into the
|
||||
/// `outlives_requirements` vector.
|
||||
#[instrument(
|
||||
skip(self, body, propagated_outlives_requirements, errors_buffer),
|
||||
level = "debug"
|
||||
)]
|
||||
#[instrument(skip(self, propagated_outlives_requirements, errors_buffer), level = "debug")]
|
||||
fn check_universal_region(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
longer_fr: RegionVid,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
@ -1583,7 +1573,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
|
||||
longer_fr,
|
||||
representative,
|
||||
body,
|
||||
propagated_outlives_requirements,
|
||||
) {
|
||||
errors_buffer.push(RegionErrorKind::RegionError {
|
||||
@ -1603,7 +1592,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
|
||||
longer_fr,
|
||||
shorter_fr,
|
||||
body,
|
||||
propagated_outlives_requirements,
|
||||
) {
|
||||
// We only report the first region error. Subsequent errors are hidden so as
|
||||
@ -1628,7 +1616,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
longer_fr: RegionVid,
|
||||
shorter_fr: RegionVid,
|
||||
body: &Body<'tcx>,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
) -> RegionRelationCheckResult {
|
||||
// If it is known that `fr: o`, carry on.
|
||||
@ -1644,7 +1631,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
self.try_propagate_universal_region_error(
|
||||
longer_fr,
|
||||
shorter_fr,
|
||||
body,
|
||||
propagated_outlives_requirements,
|
||||
)
|
||||
}
|
||||
@ -1656,7 +1642,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
longer_fr: RegionVid,
|
||||
shorter_fr: RegionVid,
|
||||
body: &Body<'tcx>,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
) -> RegionRelationCheckResult {
|
||||
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
||||
@ -1668,7 +1653,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
|
||||
|
||||
let blame_span_category = self.find_outlives_blame_span(
|
||||
body,
|
||||
longer_fr,
|
||||
NllRegionVariableOrigin::FreeRegion,
|
||||
shorter_fr,
|
||||
@ -1822,50 +1806,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
pub(crate) fn retrieve_closure_constraint_info(
|
||||
&self,
|
||||
_body: &Body<'tcx>,
|
||||
constraint: &OutlivesConstraint<'tcx>,
|
||||
) -> BlameConstraint<'tcx> {
|
||||
let loc = match constraint.locations {
|
||||
Locations::All(span) => {
|
||||
return BlameConstraint {
|
||||
category: constraint.category,
|
||||
from_closure: false,
|
||||
cause: ObligationCause::dummy_with_span(span),
|
||||
variance_info: constraint.variance_info,
|
||||
};
|
||||
constraint: OutlivesConstraint<'tcx>,
|
||||
) -> Option<(ConstraintCategory<'tcx>, Span)> {
|
||||
match constraint.locations {
|
||||
Locations::All(_) => None,
|
||||
Locations::Single(loc) => {
|
||||
self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)).copied()
|
||||
}
|
||||
Locations::Single(loc) => loc,
|
||||
};
|
||||
|
||||
let opt_span_category =
|
||||
self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
|
||||
opt_span_category
|
||||
.map(|&(category, span)| BlameConstraint {
|
||||
category,
|
||||
from_closure: true,
|
||||
cause: ObligationCause::dummy_with_span(span),
|
||||
variance_info: constraint.variance_info,
|
||||
})
|
||||
.unwrap_or(BlameConstraint {
|
||||
category: constraint.category,
|
||||
from_closure: false,
|
||||
cause: ObligationCause::dummy_with_span(constraint.span),
|
||||
variance_info: constraint.variance_info,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
|
||||
pub(crate) fn find_outlives_blame_span(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
fr1: RegionVid,
|
||||
fr1_origin: NllRegionVariableOrigin,
|
||||
fr2: RegionVid,
|
||||
) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
|
||||
let BlameConstraint { category, cause, .. } =
|
||||
self.best_blame_constraint(body, fr1, fr1_origin, |r| {
|
||||
self.provides_universal_region(r, fr1, fr2)
|
||||
});
|
||||
let BlameConstraint { category, cause, .. } = self
|
||||
.best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2))
|
||||
.0;
|
||||
(category, cause)
|
||||
}
|
||||
|
||||
@ -1970,7 +1930,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
|
||||
/// Finds some region R such that `fr1: R` and `R` is live at `elem`.
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
#[instrument(skip(self), level = "trace", ret)]
|
||||
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
|
||||
trace!(scc = ?self.constraint_sccs.scc(fr1));
|
||||
trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
|
||||
@ -2048,23 +2008,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// creating a constraint path that forces `R` to outlive
|
||||
/// `from_region`, and then finding the best choices within that
|
||||
/// path to blame.
|
||||
#[instrument(level = "debug", skip(self, target_test))]
|
||||
pub(crate) fn best_blame_constraint(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
from_region: RegionVid,
|
||||
from_region_origin: NllRegionVariableOrigin,
|
||||
target_test: impl Fn(RegionVid) -> bool,
|
||||
) -> BlameConstraint<'tcx> {
|
||||
debug!(
|
||||
"best_blame_constraint(from_region={:?}, from_region_origin={:?})",
|
||||
from_region, from_region_origin
|
||||
);
|
||||
|
||||
) -> (BlameConstraint<'tcx>, Vec<ExtraConstraintInfo>) {
|
||||
// Find all paths
|
||||
let (path, target_region) =
|
||||
self.find_constraint_paths_between_regions(from_region, target_test).unwrap();
|
||||
debug!(
|
||||
"best_blame_constraint: path={:#?}",
|
||||
"path={:#?}",
|
||||
path.iter()
|
||||
.map(|c| format!(
|
||||
"{:?} ({:?}: {:?})",
|
||||
@ -2075,6 +2030,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
let mut extra_info = vec![];
|
||||
for constraint in path.iter() {
|
||||
let outlived = constraint.sub;
|
||||
let Some(origin) = self.var_infos.get(outlived) else { continue; };
|
||||
let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin else { continue; };
|
||||
debug!(?constraint, ?p);
|
||||
let ConstraintCategory::Predicate(span) = constraint.category else { continue; };
|
||||
extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span));
|
||||
// We only want to point to one
|
||||
break;
|
||||
}
|
||||
|
||||
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
|
||||
// Instead, we use it to produce an improved `ObligationCauseCode`.
|
||||
// FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
|
||||
@ -2100,23 +2067,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
|
||||
.iter()
|
||||
.map(|constraint| {
|
||||
if constraint.category == ConstraintCategory::ClosureBounds {
|
||||
self.retrieve_closure_constraint_info(body, &constraint)
|
||||
} else {
|
||||
BlameConstraint {
|
||||
category: constraint.category,
|
||||
from_closure: false,
|
||||
cause: ObligationCause::new(
|
||||
constraint.span,
|
||||
CRATE_HIR_ID,
|
||||
cause_code.clone(),
|
||||
),
|
||||
variance_info: constraint.variance_info,
|
||||
}
|
||||
let (category, span, from_closure, cause_code) =
|
||||
if constraint.category == ConstraintCategory::ClosureBounds {
|
||||
if let Some((category, span)) =
|
||||
self.retrieve_closure_constraint_info(*constraint)
|
||||
{
|
||||
(category, span, true, ObligationCauseCode::MiscObligation)
|
||||
} else {
|
||||
(
|
||||
constraint.category,
|
||||
constraint.span,
|
||||
false,
|
||||
ObligationCauseCode::MiscObligation,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(constraint.category, constraint.span, false, cause_code.clone())
|
||||
};
|
||||
BlameConstraint {
|
||||
category,
|
||||
from_closure,
|
||||
cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code),
|
||||
variance_info: constraint.variance_info,
|
||||
outlives_constraint: *constraint,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
debug!("best_blame_constraint: categorized_path={:#?}", categorized_path);
|
||||
debug!("categorized_path={:#?}", categorized_path);
|
||||
|
||||
// To find the best span to cite, we first try to look for the
|
||||
// final constraint that is interesting and where the `sup` is
|
||||
@ -2214,10 +2191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let best_choice =
|
||||
if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
|
||||
|
||||
debug!(
|
||||
"best_blame_constraint: best_choice={:?} blame_source={}",
|
||||
best_choice, blame_source
|
||||
);
|
||||
debug!(?best_choice, ?blame_source, ?extra_info);
|
||||
|
||||
if let Some(i) = best_choice {
|
||||
if let Some(next) = categorized_path.get(i + 1) {
|
||||
@ -2226,7 +2200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
{
|
||||
// The return expression is being influenced by the return type being
|
||||
// impl Trait, point at the return type and not the return expr.
|
||||
return next.clone();
|
||||
return (next.clone(), extra_info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2246,7 +2220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
return categorized_path[i].clone();
|
||||
return (categorized_path[i].clone(), extra_info);
|
||||
}
|
||||
|
||||
// If that search fails, that is.. unusual. Maybe everything
|
||||
@ -2254,9 +2228,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// appears to be the most interesting point to report to the
|
||||
// user via an even more ad-hoc guess.
|
||||
categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
|
||||
debug!("best_blame_constraint: sorted_path={:#?}", categorized_path);
|
||||
debug!("sorted_path={:#?}", categorized_path);
|
||||
|
||||
categorized_path.remove(0)
|
||||
(categorized_path.remove(0), extra_info)
|
||||
}
|
||||
|
||||
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
@ -2338,7 +2312,13 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||
outlives_requirement={:?}",
|
||||
region, outlived_region, outlives_requirement,
|
||||
);
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region))
|
||||
(
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(
|
||||
region.into(),
|
||||
outlived_region,
|
||||
)),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
)
|
||||
}
|
||||
|
||||
ClosureOutlivesSubject::Ty(ty) => {
|
||||
@ -2348,7 +2328,10 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||
outlives_requirement={:?}",
|
||||
ty, outlived_region, outlives_requirement,
|
||||
);
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region))
|
||||
(
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -2362,4 +2345,5 @@ pub struct BlameConstraint<'tcx> {
|
||||
pub from_closure: bool,
|
||||
pub cause: ObligationCause<'tcx>,
|
||||
pub variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
pub outlives_constraint: OutlivesConstraint<'tcx>,
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@ use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::TraitEngineExt as _;
|
||||
|
||||
use crate::session_diagnostics::ConstNotUsedTraitAlias;
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
@ -58,7 +60,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
|
||||
/// which has no `external_name` in which case we use `'empty` as the
|
||||
/// region to pass to `infer_opaque_definition_from_instantiation`.
|
||||
#[instrument(level = "debug", skip(self, infcx))]
|
||||
#[instrument(level = "debug", skip(self, infcx), ret)]
|
||||
pub(crate) fn infer_opaque_types(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
@ -107,7 +109,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
.iter()
|
||||
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
|
||||
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
|
||||
.unwrap_or(infcx.tcx.lifetimes.re_root_empty),
|
||||
.unwrap_or(infcx.tcx.lifetimes.re_erased),
|
||||
_ => region,
|
||||
});
|
||||
|
||||
@ -431,7 +433,7 @@ struct ReverseMapper<'tcx> {
|
||||
|
||||
key: ty::OpaqueTypeKey<'tcx>,
|
||||
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
|
||||
map_missing_regions_to_empty: bool,
|
||||
do_not_error: bool,
|
||||
|
||||
/// initially `Some`, set to `None` once error has been reported
|
||||
hidden_ty: Option<Ty<'tcx>>,
|
||||
@ -448,29 +450,19 @@ impl<'tcx> ReverseMapper<'tcx> {
|
||||
hidden_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
key,
|
||||
map,
|
||||
map_missing_regions_to_empty: false,
|
||||
hidden_ty: Some(hidden_ty),
|
||||
span,
|
||||
}
|
||||
Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span }
|
||||
}
|
||||
|
||||
fn fold_kind_mapping_missing_regions_to_empty(
|
||||
&mut self,
|
||||
kind: GenericArg<'tcx>,
|
||||
) -> GenericArg<'tcx> {
|
||||
assert!(!self.map_missing_regions_to_empty);
|
||||
self.map_missing_regions_to_empty = true;
|
||||
fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
|
||||
assert!(!self.do_not_error);
|
||||
self.do_not_error = true;
|
||||
let kind = kind.fold_with(self);
|
||||
self.map_missing_regions_to_empty = false;
|
||||
self.do_not_error = false;
|
||||
kind
|
||||
}
|
||||
|
||||
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
|
||||
assert!(!self.map_missing_regions_to_empty);
|
||||
assert!(!self.do_not_error);
|
||||
kind.fold_with(self)
|
||||
}
|
||||
}
|
||||
@ -494,9 +486,9 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
ty::ReErased => return r,
|
||||
|
||||
// The regions that we expect from borrow checking.
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {}
|
||||
|
||||
ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
|
||||
ty::RePlaceholder(_) | ty::ReVar(_) => {
|
||||
// All of the regions in the type should either have been
|
||||
// erased by writeback, or mapped back to named regions by
|
||||
// borrow checking.
|
||||
@ -508,7 +500,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
match self.map.get(&r.into()).map(|k| k.unpack()) {
|
||||
Some(GenericArgKind::Lifetime(r1)) => r1,
|
||||
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
|
||||
None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
|
||||
None if self.do_not_error => self.tcx.lifetimes.re_static,
|
||||
None if generics.parent.is_some() => {
|
||||
if let Some(hidden_ty) = self.hidden_ty.take() {
|
||||
unexpected_hidden_region_diagnostic(
|
||||
@ -520,7 +512,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.tcx.lifetimes.re_root_empty
|
||||
self.tcx.lifetimes.re_static
|
||||
}
|
||||
None => {
|
||||
self.tcx
|
||||
@ -572,7 +564,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
self.fold_kind_no_missing_regions_error(kind)
|
||||
} else {
|
||||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
@ -587,7 +579,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
self.fold_kind_no_missing_regions_error(kind)
|
||||
} else {
|
||||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
@ -639,17 +631,10 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
Some(GenericArgKind::Const(c1)) => c1,
|
||||
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
|
||||
None => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
self.span,
|
||||
&format!(
|
||||
"const parameter `{}` is part of concrete type but not \
|
||||
used in parameter list for the `impl Trait` type alias",
|
||||
ct
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
|
||||
ct: ct.to_string(),
|
||||
span: self.span,
|
||||
});
|
||||
|
||||
self.tcx().const_error(ct.ty())
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ impl RegionValueElements {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block: IndexVec<BasicBlock, usize> = body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
@ -37,7 +37,7 @@ impl RegionValueElements {
|
||||
debug!("RegionValueElements: num_points={:#?}", num_points);
|
||||
|
||||
let mut basic_blocks = IndexVec::with_capacity(num_points);
|
||||
for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
|
||||
use rustc_middle::mir::visit::{MutVisitor, TyContext};
|
||||
use rustc_middle::mir::{Body, Location, Promoted};
|
||||
use rustc_middle::mir::{Constant, ConstantKind};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
@ -37,6 +38,21 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
// FIXME(valtrees): This function is necessary because `fold_regions`
|
||||
// panics for mir constants in the visitor.
|
||||
//
|
||||
// Once `visit_mir_constant` is removed we can also remove this function
|
||||
// and just use `renumber_regions`.
|
||||
fn renumber_regions_in_mir_constant<'tcx>(
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
value: ConstantKind<'tcx>,
|
||||
) -> ConstantKind<'tcx> {
|
||||
infcx.tcx.super_fold_regions(value, |_region, _depth| {
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall: false };
|
||||
infcx.next_nll_region_var(origin)
|
||||
})
|
||||
}
|
||||
|
||||
struct NllVisitor<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
@ -48,6 +64,13 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
|
||||
{
|
||||
renumber_regions(self.infcx, value)
|
||||
}
|
||||
|
||||
fn renumber_regions_in_mir_constant(
|
||||
&mut self,
|
||||
value: ConstantKind<'tcx>,
|
||||
) -> ConstantKind<'tcx> {
|
||||
renumber_regions_in_mir_constant(self.infcx, value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
|
||||
@ -77,7 +100,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
|
||||
debug!(?region);
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, constant: &mut ty::Const<'tcx>, _location: Location) {
|
||||
*constant = self.renumber_regions(*constant);
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) {
|
||||
let literal = constant.literal;
|
||||
constant.literal = self.renumber_regions_in_mir_constant(literal);
|
||||
debug!("constant: {:#?}", constant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_errors::{IntoDiagnosticArg, MultiSpan};
|
||||
use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::diagnostics::RegionName;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::move_unsized, code = "E0161")]
|
||||
#[diag(borrowck::move_unsized, code = "E0161")]
|
||||
pub(crate) struct MoveUnsized<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
@ -12,7 +15,7 @@ pub(crate) struct MoveUnsized<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::higher_ranked_lifetime_error)]
|
||||
#[diag(borrowck::higher_ranked_lifetime_error)]
|
||||
pub(crate) struct HigherRankedLifetimeError {
|
||||
#[subdiagnostic]
|
||||
pub cause: Option<HigherRankedErrorCause>,
|
||||
@ -29,16 +32,128 @@ pub(crate) enum HigherRankedErrorCause {
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::higher_ranked_subtype_error)]
|
||||
#[diag(borrowck::higher_ranked_subtype_error)]
|
||||
pub(crate) struct HigherRankedSubtypeError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::generic_does_not_live_long_enough)]
|
||||
#[diag(borrowck::generic_does_not_live_long_enough)]
|
||||
pub(crate) struct GenericDoesNotLiveLongEnough {
|
||||
pub kind: String,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(borrowck::var_does_not_need_mut)]
|
||||
pub(crate) struct VarNeedNotMut {
|
||||
#[suggestion_short(applicability = "machine-applicable", code = "")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(borrowck::const_not_used_in_type_alias)]
|
||||
pub(crate) struct ConstNotUsedTraitAlias {
|
||||
pub ct: String,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(borrowck::var_cannot_escape_closure)]
|
||||
#[note]
|
||||
#[note(borrowck::cannot_escape)]
|
||||
pub(crate) struct FnMutError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub ty_err: FnMutReturnTypeErr,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub(crate) enum VarHereDenote {
|
||||
#[label(borrowck::var_here_captured)]
|
||||
Captured {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck::var_here_defined)]
|
||||
Defined {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck::closure_inferred_mut)]
|
||||
FnMutInferred {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub(crate) enum FnMutReturnTypeErr {
|
||||
#[label(borrowck::returned_closure_escaped)]
|
||||
ReturnClosure {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck::returned_async_block_escaped)]
|
||||
ReturnAsyncBlock {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck::returned_ref_escaped)]
|
||||
ReturnRef {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(borrowck::lifetime_constraints_error)]
|
||||
pub(crate) struct LifetimeOutliveErr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
||||
#[label(borrowck::returned_lifetime_wrong)]
|
||||
WrongReturn {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
mir_def_name: &'a str,
|
||||
outlived_fr_name: RegionName,
|
||||
fr_name: &'a RegionName,
|
||||
},
|
||||
#[label(borrowck::returned_lifetime_short)]
|
||||
ShortReturn {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
category_desc: &'static str,
|
||||
free_region_name: &'a RegionName,
|
||||
outlived_fr_name: RegionName,
|
||||
},
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for &RegionName {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
format!("{}", self).into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for RegionName {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
format!("{}", self).into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub(crate) enum RequireStaticErr {
|
||||
#[note(borrowck::used_impl_require_static)]
|
||||
UsedImpl {
|
||||
#[primary_span]
|
||||
multi_span: MultiSpan,
|
||||
},
|
||||
}
|
||||
|
||||
@ -24,8 +24,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
/// **Any `rustc_infer::infer` operations that might generate region
|
||||
/// constraints should occur within this method so that those
|
||||
/// constraints can be properly localized!**
|
||||
#[instrument(skip(self, category, op), level = "trace")]
|
||||
pub(super) fn fully_perform_op<R, Op>(
|
||||
#[instrument(skip(self, op), level = "trace")]
|
||||
pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
|
||||
&mut self,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
@ -39,6 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
|
||||
let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
|
||||
|
||||
debug!(?output, ?constraints);
|
||||
|
||||
if let Some(data) = constraints {
|
||||
self.push_region_constraints(locations, category, data);
|
||||
}
|
||||
@ -90,17 +92,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
locations: Locations,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
self.prove_predicates(
|
||||
Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||
self.prove_predicate(
|
||||
ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}))),
|
||||
}))
|
||||
.to_predicate(self.tcx()),
|
||||
locations,
|
||||
category,
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn normalize_and_prove_instantiated_predicates(
|
||||
&mut self,
|
||||
// Keep this parameter for now, in case we start using
|
||||
@ -115,8 +119,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
.zip(instantiated_predicates.spans.into_iter())
|
||||
{
|
||||
debug!(?predicate);
|
||||
let predicate = self.normalize(predicate, locations);
|
||||
self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
|
||||
let category = ConstraintCategory::Predicate(span);
|
||||
let predicate = self.normalize_with_category(predicate, locations, category);
|
||||
self.prove_predicate(predicate, locations, category);
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,15 +157,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
|
||||
where
|
||||
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||
{
|
||||
self.normalize_with_category(value, location, ConstraintCategory::Boring)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(super) fn normalize_with_category<T>(
|
||||
&mut self,
|
||||
value: T,
|
||||
location: impl NormalizeLocation,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) -> T
|
||||
where
|
||||
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||
{
|
||||
let param_env = self.param_env;
|
||||
self.fully_perform_op(
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
category,
|
||||
param_env.and(type_op::normalize::Normalize::new(value)),
|
||||
)
|
||||
.unwrap_or_else(|NoSolution| {
|
||||
|
||||
@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
||||
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::TypeVisitable;
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
@ -86,7 +86,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
|
||||
fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
|
||||
debug!("generate: constraints at: {:#?}", self.locations);
|
||||
|
||||
// Extract out various useful fields we'll need below.
|
||||
@ -98,34 +98,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
// region constraints like `for<'a> 'a: 'b`. At some point
|
||||
// when we move to universes, we will, and this assertion
|
||||
// will start to fail.
|
||||
let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| {
|
||||
bug!("query_constraint {:?} contained bound vars", query_constraint,);
|
||||
});
|
||||
let ty::OutlivesPredicate(k1, r2) =
|
||||
query_constraint.0.no_bound_vars().unwrap_or_else(|| {
|
||||
bug!("query_constraint {:?} contained bound vars", query_constraint,);
|
||||
});
|
||||
|
||||
let constraint_category = query_constraint.1;
|
||||
|
||||
match k1.unpack() {
|
||||
GenericArgKind::Lifetime(r1) => {
|
||||
let r1_vid = self.to_region_vid(r1);
|
||||
let r2_vid = self.to_region_vid(r2);
|
||||
self.add_outlives(r1_vid, r2_vid);
|
||||
self.add_outlives(r1_vid, r2_vid, constraint_category);
|
||||
}
|
||||
|
||||
GenericArgKind::Type(mut t1) => {
|
||||
GenericArgKind::Type(t1) => {
|
||||
// we don't actually use this for anything, but
|
||||
// the `TypeOutlives` code needs an origin.
|
||||
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
|
||||
|
||||
// Placeholder regions need to be converted now because it may
|
||||
// create new region variables, which can't be done later when
|
||||
// verifying these bounds.
|
||||
if t1.has_placeholders() {
|
||||
t1 = tcx.fold_regions(t1, |r, _| match *r {
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder)
|
||||
}
|
||||
_ => r,
|
||||
});
|
||||
}
|
||||
|
||||
TypeOutlives::new(
|
||||
&mut *self,
|
||||
tcx,
|
||||
@ -133,7 +124,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
Some(implicit_region_bound),
|
||||
param_env,
|
||||
)
|
||||
.type_must_outlive(origin, t1, r2);
|
||||
.type_must_outlive(origin, t1, r2, constraint_category);
|
||||
}
|
||||
|
||||
GenericArgKind::Const(_) => {
|
||||
@ -143,6 +134,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Placeholder regions need to be converted eagerly because it may
|
||||
/// create new region variables, which we must not do when verifying
|
||||
/// our region bounds.
|
||||
///
|
||||
/// FIXME: This should get removed once higher ranked region obligations
|
||||
/// are dealt with during trait solving.
|
||||
fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
|
||||
if value.has_placeholders() {
|
||||
self.tcx.fold_regions(value, |r, _| match *r {
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder)
|
||||
}
|
||||
_ => r,
|
||||
})
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_to_type_test(
|
||||
&mut self,
|
||||
generic_kind: GenericKind<'tcx>,
|
||||
@ -150,7 +160,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
verify_bound: VerifyBound<'tcx>,
|
||||
) -> TypeTest<'tcx> {
|
||||
let lower_bound = self.to_region_vid(region);
|
||||
|
||||
TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
|
||||
}
|
||||
|
||||
@ -162,10 +171,19 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
|
||||
fn add_outlives(
|
||||
&mut self,
|
||||
sup: ty::RegionVid,
|
||||
sub: ty::RegionVid,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
let category = match self.category {
|
||||
ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
|
||||
_ => self.category,
|
||||
};
|
||||
self.constraints.outlives_constraints.push(OutlivesConstraint {
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
category,
|
||||
span: self.span,
|
||||
sub,
|
||||
sup,
|
||||
@ -185,10 +203,11 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
|
||||
_origin: SubregionOrigin<'tcx>,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
constraint_category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
let b = self.to_region_vid(b);
|
||||
let a = self.to_region_vid(a);
|
||||
self.add_outlives(b, a);
|
||||
self.add_outlives(b, a, constraint_category);
|
||||
}
|
||||
|
||||
fn push_verify(
|
||||
@ -198,6 +217,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
|
||||
a: ty::Region<'tcx>,
|
||||
bound: VerifyBound<'tcx>,
|
||||
) {
|
||||
let kind = self.replace_placeholders_with_nll(kind);
|
||||
let bound = self.replace_placeholders_with_nll(bound);
|
||||
let type_test = self.verify_to_type_test(kind, a, bound);
|
||||
self.add_type_test(type_test);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
@ -61,25 +61,13 @@ pub(crate) fn create<'tcx>(
|
||||
constraints,
|
||||
universal_regions: universal_regions.clone(),
|
||||
region_bound_pairs: Default::default(),
|
||||
relations: UniversalRegionRelations {
|
||||
universal_regions: universal_regions.clone(),
|
||||
outlives: Default::default(),
|
||||
inverse_outlives: Default::default(),
|
||||
},
|
||||
outlives: Default::default(),
|
||||
inverse_outlives: Default::default(),
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
impl UniversalRegionRelations<'_> {
|
||||
/// Records in the `outlives_relation` (and
|
||||
/// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
|
||||
/// builder below.
|
||||
fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
|
||||
debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
|
||||
self.outlives.add(fr_a, fr_b);
|
||||
self.inverse_outlives.add(fr_b, fr_a);
|
||||
}
|
||||
|
||||
/// Given two universal regions, returns the postdominating
|
||||
/// upper-bound (effectively the least upper bound).
|
||||
///
|
||||
@ -216,11 +204,20 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> {
|
||||
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
||||
|
||||
// outputs:
|
||||
relations: UniversalRegionRelations<'tcx>,
|
||||
outlives: TransitiveRelationBuilder<RegionVid>,
|
||||
inverse_outlives: TransitiveRelationBuilder<RegionVid>,
|
||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
/// Records in the `outlives_relation` (and
|
||||
/// `inverse_outlives_relation`) that `fr_a: fr_b`.
|
||||
fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
|
||||
debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
|
||||
self.outlives.add(fr_a, fr_b);
|
||||
self.inverse_outlives.add(fr_b, fr_a);
|
||||
}
|
||||
|
||||
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
|
||||
let unnormalized_input_output_tys = self
|
||||
.universal_regions
|
||||
@ -242,10 +239,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
let constraint_sets: Vec<_> = unnormalized_input_output_tys
|
||||
.flat_map(|ty| {
|
||||
debug!("build: input_or_output={:?}", ty);
|
||||
// We only add implied bounds for the normalized type as the unnormalized
|
||||
// type may not actually get checked by the caller.
|
||||
//
|
||||
// Can otherwise be unsound, see #91068.
|
||||
// We add implied bounds from both the unnormalized and normalized ty.
|
||||
// See issue #87748
|
||||
let constraints_implied1 = self.add_implied_bounds(ty);
|
||||
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
@ -269,13 +265,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
// }
|
||||
// impl Foo for () {
|
||||
// type Bar = ();
|
||||
// fn foo(&self) ->&() {}
|
||||
// fn foo(&self) -> &() {}
|
||||
// }
|
||||
// ```
|
||||
// Both &Self::Bar and &() are WF
|
||||
let constraints_implied = self.add_implied_bounds(norm_ty);
|
||||
let constraints_implied2 =
|
||||
if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
|
||||
normalized_inputs_and_output.push(norm_ty);
|
||||
constraints1.into_iter().chain(constraints_implied)
|
||||
constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -292,9 +289,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
let fr_fn_body = self.universal_regions.fr_fn_body;
|
||||
for fr in self.universal_regions.universal_regions() {
|
||||
debug!("build: relating free region {:?} to itself and to 'static", fr);
|
||||
self.relations.relate_universal_regions(fr, fr);
|
||||
self.relations.relate_universal_regions(fr_static, fr);
|
||||
self.relations.relate_universal_regions(fr, fr_fn_body);
|
||||
self.relate_universal_regions(fr, fr);
|
||||
self.relate_universal_regions(fr_static, fr);
|
||||
self.relate_universal_regions(fr, fr_fn_body);
|
||||
}
|
||||
|
||||
for data in &constraint_sets {
|
||||
@ -313,7 +310,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
}
|
||||
|
||||
CreateResult {
|
||||
universal_region_relations: Frozen::freeze(self.relations),
|
||||
universal_region_relations: Frozen::freeze(UniversalRegionRelations {
|
||||
universal_regions: self.universal_regions,
|
||||
outlives: self.outlives.freeze(),
|
||||
inverse_outlives: self.inverse_outlives.freeze(),
|
||||
}),
|
||||
region_bound_pairs: self.region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
}
|
||||
@ -346,17 +347,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
|
||||
match outlives_bound {
|
||||
OutlivesBound::RegionSubRegion(r1, r2) => {
|
||||
// `where Type:` is lowered to `where Type: 'empty` so that
|
||||
// we check `Type` is well formed, but there's no use for
|
||||
// this bound here.
|
||||
if r1.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// The bound says that `r1 <= r2`; we store `r2: r1`.
|
||||
let r1 = self.universal_regions.to_region_vid(r1);
|
||||
let r2 = self.universal_regions.to_region_vid(r2);
|
||||
self.relations.relate_universal_regions(r2, r1);
|
||||
self.relate_universal_regions(r2, r1);
|
||||
}
|
||||
|
||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||
|
||||
@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::{
|
||||
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
|
||||
OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
|
||||
OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType,
|
||||
UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
@ -178,97 +179,15 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
upvars,
|
||||
};
|
||||
|
||||
let opaque_type_values = type_check_internal(
|
||||
infcx,
|
||||
param_env,
|
||||
body,
|
||||
promoted,
|
||||
®ion_bound_pairs,
|
||||
implicit_region_bound,
|
||||
&mut borrowck_context,
|
||||
|mut cx| {
|
||||
debug!("inside extra closure of type_check_internal");
|
||||
cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
|
||||
liveness::generate(
|
||||
&mut cx,
|
||||
body,
|
||||
elements,
|
||||
flow_inits,
|
||||
move_data,
|
||||
location_table,
|
||||
use_polonius,
|
||||
);
|
||||
|
||||
translate_outlives_facts(&mut cx);
|
||||
let opaque_type_values =
|
||||
infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
|
||||
opaque_type_values
|
||||
.into_iter()
|
||||
.map(|(opaque_type_key, decl)| {
|
||||
cx.fully_perform_op(
|
||||
Locations::All(body.span),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.register_member_constraints(
|
||||
param_env,
|
||||
opaque_type_key,
|
||||
decl.hidden_type.ty,
|
||||
decl.hidden_type.span,
|
||||
);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
||||
trace!(
|
||||
"finalized opaque type {:?} to {:#?}",
|
||||
opaque_type_key,
|
||||
hidden_type.ty.kind()
|
||||
);
|
||||
if hidden_type.has_infer_types_or_consts() {
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
decl.hidden_type.span,
|
||||
&format!("could not resolve {:#?}", hidden_type.ty.kind()),
|
||||
);
|
||||
hidden_type.ty = infcx.tcx.ty_error();
|
||||
}
|
||||
|
||||
(opaque_type_key, (hidden_type, decl.origin))
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
);
|
||||
|
||||
MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
|
||||
level = "debug"
|
||||
)]
|
||||
fn type_check_internal<'a, 'tcx, R>(
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
promoted: &'a IndexVec<Promoted, Body<'tcx>>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
|
||||
) -> R {
|
||||
debug!("body: {:#?}", body);
|
||||
let mut checker = TypeChecker::new(
|
||||
infcx,
|
||||
body,
|
||||
param_env,
|
||||
region_bound_pairs,
|
||||
®ion_bound_pairs,
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
&mut borrowck_context,
|
||||
);
|
||||
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, promoted);
|
||||
verifier.visit_body(&body);
|
||||
@ -280,7 +199,56 @@ fn type_check_internal<'a, 'tcx, R>(
|
||||
checker.typeck_mir(body);
|
||||
}
|
||||
|
||||
extra(checker)
|
||||
checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
|
||||
liveness::generate(
|
||||
&mut checker,
|
||||
body,
|
||||
elements,
|
||||
flow_inits,
|
||||
move_data,
|
||||
location_table,
|
||||
use_polonius,
|
||||
);
|
||||
|
||||
translate_outlives_facts(&mut checker);
|
||||
let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
|
||||
let opaque_type_values = opaque_type_values
|
||||
.into_iter()
|
||||
.map(|(opaque_type_key, decl)| {
|
||||
checker
|
||||
.fully_perform_op(
|
||||
Locations::All(body.span),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.register_member_constraints(
|
||||
param_env,
|
||||
opaque_type_key,
|
||||
decl.hidden_type.ty,
|
||||
decl.hidden_type.span,
|
||||
);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
||||
trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
|
||||
if hidden_type.has_infer_types_or_consts() {
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
decl.hidden_type.span,
|
||||
&format!("could not resolve {:#?}", hidden_type.ty.kind()),
|
||||
);
|
||||
hidden_type.ty = infcx.tcx.ty_error();
|
||||
}
|
||||
|
||||
(opaque_type_key, (hidden_type, decl.origin))
|
||||
})
|
||||
.collect();
|
||||
|
||||
MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
|
||||
}
|
||||
|
||||
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
|
||||
@ -344,6 +312,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
||||
debug!(?constant, ?location, "visit_constant");
|
||||
|
||||
self.super_constant(constant, location);
|
||||
let ty = self.sanitize_type(constant, constant.literal.ty());
|
||||
|
||||
@ -387,11 +357,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let maybe_uneval = match constant.literal {
|
||||
ConstantKind::Ty(ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => Some(uv),
|
||||
ty::ConstKind::Unevaluated(_) => {
|
||||
bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(uv) = maybe_uneval {
|
||||
if let Some(promoted) = uv.promoted {
|
||||
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
|
||||
@ -1076,6 +1050,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
|
||||
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
||||
debug!(?annotation);
|
||||
match annotation {
|
||||
UserType::Ty(mut ty) => {
|
||||
ty = self.normalize(ty, Locations::All(span));
|
||||
@ -1334,12 +1309,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
..
|
||||
}) => span_bug!(
|
||||
stmt.source_info.span,
|
||||
"Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
|
||||
),
|
||||
StatementKind::Intrinsic(box ref kind) => match kind {
|
||||
NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
|
||||
NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
|
||||
stmt.source_info.span,
|
||||
"Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics",
|
||||
),
|
||||
},
|
||||
StatementKind::FakeRead(..)
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
@ -1448,9 +1424,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
))
|
||||
});
|
||||
debug!(?sig);
|
||||
let sig = self.normalize(sig, term_location);
|
||||
self.check_call_dest(body, term, &sig, *destination, target, term_location);
|
||||
|
||||
// IMPORTANT: We have to prove well formed for the function signature before
|
||||
// we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
|
||||
// get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
|
||||
//
|
||||
// Normalization results in a well formed type if the input is well formed, so we
|
||||
// don't have to check it twice.
|
||||
//
|
||||
// See #91068 for an example.
|
||||
self.prove_predicates(
|
||||
sig.inputs_and_output
|
||||
.iter()
|
||||
@ -1458,6 +1439,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
term_location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
);
|
||||
let sig = self.normalize(sig, term_location);
|
||||
self.check_call_dest(body, term, &sig, *destination, target, term_location);
|
||||
|
||||
// The ordinary liveness rules will ensure that all
|
||||
// regions in the type of the callee are live here. We
|
||||
@ -1834,14 +1817,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
||||
debug!(?op, ?location, "check_operand");
|
||||
|
||||
if let Operand::Constant(constant) = op {
|
||||
let maybe_uneval = match constant.literal {
|
||||
ConstantKind::Ty(ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => Some(uv),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
|
||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
||||
};
|
||||
|
||||
if let Some(uv) = maybe_uneval {
|
||||
if uv.promoted.is_none() {
|
||||
let tcx = self.tcx();
|
||||
@ -1904,7 +1887,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
&Rvalue::NullaryOp(_, ty) => {
|
||||
&Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => {
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
@ -2033,6 +2016,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
CastKind::DynStar => {
|
||||
// get the constraints from the target type (`dyn* Clone`)
|
||||
//
|
||||
// apply them to prove that the source type `Foo` implements `Clone` etc
|
||||
let (existential_predicates, region) = match ty.kind() {
|
||||
Dynamic(predicates, region, ty::DynStar) => (predicates, region),
|
||||
_ => panic!("Invalid dyn* cast_ty"),
|
||||
};
|
||||
|
||||
let self_ty = op.ty(body, tcx);
|
||||
|
||||
self.prove_predicates(
|
||||
existential_predicates
|
||||
.iter()
|
||||
.map(|predicate| predicate.with_self_ty(tcx, self_ty)),
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
);
|
||||
|
||||
let outlives_predicate =
|
||||
tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
|
||||
ty::OutlivesPredicate(self_ty, *region),
|
||||
)));
|
||||
self.prove_predicate(
|
||||
outlives_predicate,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
);
|
||||
}
|
||||
|
||||
CastKind::Pointer(PointerCast::MutToConstPointer) => {
|
||||
let ty::RawPtr(ty::TypeAndMut {
|
||||
ty: ty_from,
|
||||
@ -2584,7 +2597,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
.enumerate()
|
||||
.filter_map(|(idx, constraint)| {
|
||||
let ty::OutlivesPredicate(k1, r2) =
|
||||
constraint.no_bound_vars().unwrap_or_else(|| {
|
||||
constraint.0.no_bound_vars().unwrap_or_else(|| {
|
||||
bug!("query_constraint {:?} contained bound vars", constraint,);
|
||||
});
|
||||
|
||||
@ -2659,7 +2672,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.check_local(&body, local, local_decl);
|
||||
}
|
||||
|
||||
for (block, block_data) in body.basic_blocks().iter_enumerated() {
|
||||
for (block, block_data) in body.basic_blocks.iter_enumerated() {
|
||||
let mut location = Location { block, statement_index: 0 };
|
||||
for stmt in &block_data.statements {
|
||||
if !stmt.source_info.span.is_dummy() {
|
||||
|
||||
@ -54,13 +54,6 @@ pub struct UniversalRegions<'tcx> {
|
||||
/// The total number of universal region variables instantiated.
|
||||
num_universals: usize,
|
||||
|
||||
/// A special region variable created for the `'empty(U0)` region.
|
||||
/// Note that this is **not** a "universal" region, as it doesn't
|
||||
/// represent a universally bound placeholder or any such thing.
|
||||
/// But we do create it here in this type because it's a useful region
|
||||
/// to have around in a few limited cases.
|
||||
pub root_empty: RegionVid,
|
||||
|
||||
/// The "defining" type for this function, with all universal
|
||||
/// regions instantiated. For a closure or generator, this is the
|
||||
/// closure type, but for a top-level function it's the `FnDef`.
|
||||
@ -323,11 +316,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
|
||||
/// See `UniversalRegionIndices::to_region_vid`.
|
||||
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
|
||||
if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r {
|
||||
self.root_empty
|
||||
} else {
|
||||
self.indices.to_region_vid(r)
|
||||
}
|
||||
self.indices.to_region_vid(r)
|
||||
}
|
||||
|
||||
/// As part of the NLL unit tests, you can annotate a function with
|
||||
@ -501,16 +490,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let root_empty = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
|
||||
.to_region_vid();
|
||||
|
||||
UniversalRegions {
|
||||
indices,
|
||||
fr_static,
|
||||
fr_fn_body,
|
||||
root_empty,
|
||||
first_extern_index,
|
||||
first_local_index,
|
||||
num_universals,
|
||||
@ -768,10 +751,9 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
) {
|
||||
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
|
||||
let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
|
||||
for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
|
||||
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.next_nll_region_var(FR);
|
||||
debug!(?region_vid);
|
||||
|
||||
@ -7,20 +7,21 @@ edition = "2021"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc_parse_format = { path = "../rustc_parse_format" }
|
||||
tracing = "0.1"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_expand = { path = "../rustc_expand" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse_format = { path = "../rustc_parse_format" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_expand = { path = "../rustc_expand" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.8"
|
||||
tracing = "0.1"
|
||||
|
||||
@ -852,7 +852,7 @@ pub(super) fn expand_global_asm<'cx>(
|
||||
if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
|
||||
MacEager::items(smallvec![P(ast::Item {
|
||||
ident: Ident::empty(),
|
||||
attrs: Vec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
|
||||
vis: ast::Visibility {
|
||||
|
||||
@ -52,7 +52,7 @@ pub fn expand_assert<'cx>(
|
||||
let expr = if let Some(tokens) = custom_message {
|
||||
let then = cx.expr(
|
||||
call_site_span,
|
||||
ExprKind::MacCall(MacCall {
|
||||
ExprKind::MacCall(P(MacCall {
|
||||
path: panic_path(),
|
||||
args: P(MacArgs::Delimited(
|
||||
DelimSpan::from_single(call_site_span),
|
||||
@ -60,7 +60,7 @@ pub fn expand_assert<'cx>(
|
||||
tokens,
|
||||
)),
|
||||
prior_type_ascription: None,
|
||||
}),
|
||||
})),
|
||||
);
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ use rustc_span::{
|
||||
symbol::{sym, Ident, Symbol},
|
||||
Span,
|
||||
};
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub(super) struct Context<'cx, 'a> {
|
||||
// An optimization.
|
||||
@ -116,7 +117,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
self.cx.item(
|
||||
self.span,
|
||||
Ident::empty(),
|
||||
vec![self.cx.attribute(attr::mk_list_item(
|
||||
thin_vec![self.cx.attribute(attr::mk_list_item(
|
||||
Ident::new(sym::allow, self.span),
|
||||
vec![attr::mk_nested_word_item(Ident::new(sym::unused_imports, self.span))],
|
||||
))],
|
||||
@ -177,7 +178,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
});
|
||||
self.cx.expr(
|
||||
self.span,
|
||||
ExprKind::MacCall(MacCall {
|
||||
ExprKind::MacCall(P(MacCall {
|
||||
path: panic_path,
|
||||
args: P(MacArgs::Delimited(
|
||||
DelimSpan::from_single(self.span),
|
||||
@ -185,7 +186,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
initial.into_iter().chain(captures).collect::<TokenStream>(),
|
||||
)),
|
||||
prior_type_ascription: None,
|
||||
}),
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ pub fn expand_cfg(
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(builtin_macros::requires_cfg_pattern)]
|
||||
#[diag(builtin_macros::requires_cfg_pattern)]
|
||||
struct RequiresCfgPattern {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
@ -44,7 +44,7 @@ struct RequiresCfgPattern {
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(builtin_macros::expected_one_cfg_pattern)]
|
||||
#[diag(builtin_macros::expected_one_cfg_pattern)]
|
||||
struct OneCfgPattern {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
||||
@ -188,14 +188,14 @@ impl CfgEval<'_, '_> {
|
||||
let orig_tokens = annotatable.to_tokens().flattened();
|
||||
|
||||
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
||||
// to the captured `AttrAnnotatedTokenStream` (specifically, we capture
|
||||
// `AttrAnnotatedTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
|
||||
// to the captured `AttrTokenStream` (specifically, we capture
|
||||
// `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
|
||||
let mut parser =
|
||||
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
|
||||
parser.capture_cfg = true;
|
||||
annotatable = parse_annotatable_with(&mut parser);
|
||||
|
||||
// Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
|
||||
// Now that we have our re-parsed `AttrTokenStream`, recursively configuring
|
||||
// our attribute target will correctly the tokens as well.
|
||||
flat_map_annotatable(self, annotatable)
|
||||
}
|
||||
|
||||
@ -28,7 +28,13 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
|
||||
continue;
|
||||
}
|
||||
|
||||
krate.attrs.push(mk_attr(AttrStyle::Inner, path, args, start_span.to(end_span)));
|
||||
krate.attrs.push(mk_attr(
|
||||
&parse_sess.attr_id_generator,
|
||||
AttrStyle::Inner,
|
||||
path,
|
||||
args,
|
||||
start_span.to(end_span),
|
||||
));
|
||||
}
|
||||
|
||||
krate
|
||||
|
||||
@ -39,7 +39,7 @@ pub fn expand_concat(
|
||||
ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => {
|
||||
cx.span_err(e.span, "cannot concatenate a byte string literal");
|
||||
}
|
||||
ast::LitKind::Err(_) => {
|
||||
ast::LitKind::Err => {
|
||||
has_errors = true;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{ptr::P, tokenstream::TokenStream};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_expand::base::{self, DummyResult};
|
||||
|
||||
@ -43,7 +42,7 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
|
||||
ast::LitKind::Bool(_) => {
|
||||
cx.span_err(expr.span, "cannot concatenate boolean literals");
|
||||
}
|
||||
ast::LitKind::Err(_) => {}
|
||||
ast::LitKind::Err => {}
|
||||
ast::LitKind::Int(_, _) if !is_nested => {
|
||||
let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals");
|
||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
|
||||
@ -185,5 +184,5 @@ pub fn expand_concat_bytes(
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
}
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(accumulator))))
|
||||
base::MacEager::expr(cx.expr_byte_str(sp, accumulator))
|
||||
}
|
||||
|
||||
@ -32,7 +32,8 @@ impl MultiItemModifier for Expander {
|
||||
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
|
||||
let template =
|
||||
AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
|
||||
let attr = attr::mk_attr_outer(meta_item.clone());
|
||||
let attr =
|
||||
attr::mk_attr_outer(&sess.parse_sess.attr_id_generator, meta_item.clone());
|
||||
validate_attr::check_builtin_attribute(
|
||||
&sess.parse_sess,
|
||||
&attr,
|
||||
@ -126,9 +127,9 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
|
||||
}
|
||||
|
||||
fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) {
|
||||
let help_msg = match lit.token.kind {
|
||||
token::Str if rustc_lexer::is_ident(lit.token.symbol.as_str()) => {
|
||||
format!("try using `#[derive({})]`", lit.token.symbol)
|
||||
let help_msg = match lit.token_lit.kind {
|
||||
token::Str if rustc_lexer::is_ident(lit.token_lit.symbol.as_str()) => {
|
||||
format!("try using `#[derive({})]`", lit.token_lit.symbol)
|
||||
}
|
||||
_ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
|
||||
};
|
||||
|
||||
@ -15,7 +15,6 @@ pub fn expand_deriving_copy(
|
||||
) {
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: path_std!(marker::Copy),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::path_std;
|
||||
|
||||
use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn expand_deriving_clone(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
@ -68,10 +68,9 @@ pub fn expand_deriving_clone(
|
||||
}
|
||||
|
||||
let inline = cx.meta_word(span, sym::inline);
|
||||
let attrs = vec![cx.attribute(inline)];
|
||||
let attrs = thin_vec![cx.attribute(inline)];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: path_std!(clone::Clone),
|
||||
additional_bounds: bounds,
|
||||
generics: Bounds::empty(),
|
||||
|
||||
@ -7,6 +7,7 @@ use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn expand_deriving_eq(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
@ -20,10 +21,9 @@ pub fn expand_deriving_eq(
|
||||
let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
|
||||
let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
|
||||
let no_coverage = cx.meta_word(span, sym::no_coverage);
|
||||
let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
|
||||
let attrs = thin_vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: path_std!(cmp::Eq),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::path_std;
|
||||
|
||||
use rustc_ast::MetaItem;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn expand_deriving_ord(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
@ -15,10 +15,9 @@ pub fn expand_deriving_ord(
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
) {
|
||||
let inline = cx.meta_word(span, sym::inline);
|
||||
let attrs = vec![cx.attribute(inline)];
|
||||
let attrs = thin_vec![cx.attribute(inline)];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: path_std!(cmp::Ord),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::{path_local, path_std};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn expand_deriving_partial_eq(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
@ -15,14 +15,8 @@ pub fn expand_deriving_partial_eq(
|
||||
item: &Annotatable,
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
) {
|
||||
fn cs_op(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
substr: &Substructure<'_>,
|
||||
op: BinOpKind,
|
||||
combiner: BinOpKind,
|
||||
base: bool,
|
||||
) -> BlockOrExpr {
|
||||
fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||
let base = true;
|
||||
let expr = cs_fold(
|
||||
true, // use foldl
|
||||
cx,
|
||||
@ -47,39 +41,22 @@ pub fn expand_deriving_partial_eq(
|
||||
cx.expr_deref(field.span, expr.clone())
|
||||
}
|
||||
};
|
||||
cx.expr_binary(field.span, op, convert(&field.self_expr), convert(other_expr))
|
||||
cx.expr_binary(
|
||||
field.span,
|
||||
BinOpKind::Eq,
|
||||
convert(&field.self_expr),
|
||||
convert(other_expr),
|
||||
)
|
||||
}
|
||||
CsFold::Combine(span, expr1, expr2) => {
|
||||
cx.expr_binary(span, BinOpKind::And, expr1, expr2)
|
||||
}
|
||||
CsFold::Combine(span, expr1, expr2) => cx.expr_binary(span, combiner, expr1, expr2),
|
||||
CsFold::Fieldless => cx.expr_bool(span, base),
|
||||
},
|
||||
);
|
||||
BlockOrExpr::new_expr(expr)
|
||||
}
|
||||
|
||||
fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||
cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true)
|
||||
}
|
||||
fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||
cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false)
|
||||
}
|
||||
|
||||
macro_rules! md {
|
||||
($name:expr, $f:ident) => {{
|
||||
let inline = cx.meta_word(span, sym::inline);
|
||||
let attrs = vec![cx.attribute(inline)];
|
||||
MethodDef {
|
||||
name: $name,
|
||||
generics: Bounds::empty(),
|
||||
explicit_self: true,
|
||||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty: Path(path_local!(bool)),
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: true,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| $f(a, b, c))),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
super::inject_impl_of_structural_trait(
|
||||
cx,
|
||||
span,
|
||||
@ -88,17 +65,23 @@ pub fn expand_deriving_partial_eq(
|
||||
push,
|
||||
);
|
||||
|
||||
// avoid defining `ne` if we can
|
||||
// c-like enums, enums without any fields and structs without fields
|
||||
// can safely define only `eq`.
|
||||
let mut methods = vec![md!(sym::eq, cs_eq)];
|
||||
if !is_type_without_fields(item) {
|
||||
methods.push(md!(sym::ne, cs_ne));
|
||||
}
|
||||
// No need to generate `ne`, the default suffices, and not generating it is
|
||||
// faster.
|
||||
let inline = cx.meta_word(span, sym::inline);
|
||||
let attrs = thin_vec![cx.attribute(inline)];
|
||||
let methods = vec![MethodDef {
|
||||
name: sym::eq,
|
||||
generics: Bounds::empty(),
|
||||
explicit_self: true,
|
||||
nonself_args: vec![(self_ref(), sym::other)],
|
||||
ret_ty: Path(path_local!(bool)),
|
||||
attributes: attrs,
|
||||
unify_fieldless_variants: true,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
|
||||
}];
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: path_std!(cmp::PartialEq),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::{path_std, pathvec_std};
|
||||
|
||||
use rustc_ast::MetaItem;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn expand_deriving_partial_ord(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
@ -19,7 +19,7 @@ pub fn expand_deriving_partial_ord(
|
||||
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
|
||||
|
||||
let inline = cx.meta_word(span, sym::inline);
|
||||
let attrs = vec![cx.attribute(inline)];
|
||||
let attrs = thin_vec![cx.attribute(inline)];
|
||||
|
||||
let partial_cmp_def = MethodDef {
|
||||
name: sym::partial_cmp,
|
||||
@ -36,7 +36,6 @@ pub fn expand_deriving_partial_ord(
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: vec![],
|
||||
path: path_std!(cmp::PartialOrd),
|
||||
additional_bounds: vec![],
|
||||
generics: Bounds::empty(),
|
||||
|
||||
@ -19,7 +19,6 @@ pub fn expand_deriving_debug(
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: path_std!(fmt::Debug),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
@ -30,7 +29,7 @@ pub fn expand_deriving_debug(
|
||||
explicit_self: true,
|
||||
nonself_args: vec![(fmtr, sym::f)],
|
||||
ret_ty: Path(path_std!(fmt::Result)),
|
||||
attributes: Vec::new(),
|
||||
attributes: ast::AttrVec::new(),
|
||||
unify_fieldless_variants: false,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
show_substructure(a, b, c)
|
||||
@ -52,7 +51,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
||||
|
||||
// We want to make sure we have the ctxt set so that we can use unstable methods
|
||||
let span = cx.with_def_site_ctxt(span);
|
||||
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
|
||||
let name = cx.expr_str(span, ident.name);
|
||||
let fmt = substr.nonselflike_args[0].clone();
|
||||
|
||||
// Struct and tuples are similar enough that we use the same code for both,
|
||||
@ -89,10 +88,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
||||
for i in 0..fields.len() {
|
||||
let field = &fields[i];
|
||||
if is_struct {
|
||||
let name = cx.expr_lit(
|
||||
field.span,
|
||||
ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
|
||||
);
|
||||
let name = cx.expr_str(field.span, field.name.unwrap().name);
|
||||
args.push(name);
|
||||
}
|
||||
// Use an extra indirection to make sure this works for unsized types.
|
||||
@ -108,10 +104,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
||||
|
||||
for field in fields {
|
||||
if is_struct {
|
||||
name_exprs.push(cx.expr_lit(
|
||||
field.span,
|
||||
ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
|
||||
));
|
||||
name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name));
|
||||
}
|
||||
|
||||
// Use an extra indirection to make sure this works for unsized types.
|
||||
|
||||
@ -22,7 +22,6 @@ pub fn expand_deriving_rustc_decodable(
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
@ -48,7 +47,7 @@ pub fn expand_deriving_rustc_decodable(
|
||||
],
|
||||
PathKind::Std,
|
||||
)),
|
||||
attributes: Vec::new(),
|
||||
attributes: ast::AttrVec::new(),
|
||||
unify_fieldless_variants: false,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
decodable_substructure(a, b, c, krate)
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_ast::EnumDef;
|
||||
use rustc_ast::VariantData;
|
||||
use rustc_ast::{walk_list, EnumDef, VariantData};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
use smallvec::SmallVec;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn expand_deriving_default(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
@ -22,10 +20,9 @@ pub fn expand_deriving_default(
|
||||
item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
|
||||
|
||||
let inline = cx.meta_word(span, sym::inline);
|
||||
let attrs = vec![cx.attribute(inline)];
|
||||
let attrs = thin_vec![cx.attribute(inline)];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: Path::new(vec![kw::Default, sym::Default]),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
|
||||
@ -89,7 +89,7 @@ use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::pathvec_std;
|
||||
|
||||
use rustc_ast::{ExprKind, MetaItem, Mutability};
|
||||
use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
@ -106,7 +106,6 @@ pub fn expand_deriving_rustc_encodable(
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
@ -132,7 +131,7 @@ pub fn expand_deriving_rustc_encodable(
|
||||
],
|
||||
PathKind::Std,
|
||||
)),
|
||||
attributes: Vec::new(),
|
||||
attributes: AttrVec::new(),
|
||||
unify_fieldless_variants: false,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
encodable_substructure(a, b, c, krate)
|
||||
|
||||
@ -162,30 +162,28 @@
|
||||
pub use StaticFields::*;
|
||||
pub use SubstructureFields::*;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::iter;
|
||||
use std::vec;
|
||||
|
||||
use crate::deriving;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind};
|
||||
use rustc_ast::{
|
||||
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
|
||||
};
|
||||
use rustc_ast::{GenericArg, GenericParamKind, VariantData};
|
||||
use rustc_attr as attr;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::iter;
|
||||
use std::vec;
|
||||
use thin_vec::thin_vec;
|
||||
use ty::{Bounds, Path, Ref, Self_, Ty};
|
||||
|
||||
use crate::deriving;
|
||||
|
||||
pub mod ty;
|
||||
|
||||
pub struct TraitDef<'a> {
|
||||
/// The span for the current #[derive(Foo)] header.
|
||||
pub span: Span,
|
||||
|
||||
pub attributes: Vec<ast::Attribute>,
|
||||
|
||||
/// Path of the trait, including any type parameters
|
||||
pub path: Path,
|
||||
|
||||
@ -219,7 +217,7 @@ pub struct MethodDef<'a> {
|
||||
/// Returns type
|
||||
pub ret_ty: Ty,
|
||||
|
||||
pub attributes: Vec<ast::Attribute>,
|
||||
pub attributes: ast::AttrVec,
|
||||
|
||||
/// Can we combine fieldless variants for enums into a single match arm?
|
||||
/// If true, indicates that the trait operation uses the enum tag in some
|
||||
@ -383,16 +381,11 @@ fn find_type_parameters(
|
||||
}
|
||||
|
||||
// Place bound generic params on a stack, to extract them when a type is encountered.
|
||||
fn visit_poly_trait_ref(
|
||||
&mut self,
|
||||
trait_ref: &'a ast::PolyTraitRef,
|
||||
modifier: &'a ast::TraitBoundModifier,
|
||||
) {
|
||||
fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) {
|
||||
let stack_len = self.bound_generic_params_stack.len();
|
||||
self.bound_generic_params_stack
|
||||
.extend(trait_ref.bound_generic_params.clone().into_iter());
|
||||
self.bound_generic_params_stack.extend(trait_ref.bound_generic_params.iter().cloned());
|
||||
|
||||
visit::walk_poly_trait_ref(self, trait_ref, modifier);
|
||||
visit::walk_poly_trait_ref(self, trait_ref);
|
||||
|
||||
self.bound_generic_params_stack.truncate(stack_len);
|
||||
}
|
||||
@ -568,7 +561,7 @@ impl<'a> TraitDef<'a> {
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None,
|
||||
},
|
||||
attrs: Vec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
generics: Generics::default(),
|
||||
@ -609,7 +602,7 @@ impl<'a> TraitDef<'a> {
|
||||
param.bounds.iter().cloned()
|
||||
).collect();
|
||||
|
||||
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
|
||||
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span, .. } => {
|
||||
let const_nodefault_kind = GenericParamKind::Const {
|
||||
@ -644,11 +637,7 @@ impl<'a> TraitDef<'a> {
|
||||
}
|
||||
ast::WherePredicate::EqPredicate(we) => {
|
||||
let span = we.span.with_ctxt(ctxt);
|
||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
..we.clone()
|
||||
})
|
||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { span, ..we.clone() })
|
||||
}
|
||||
}
|
||||
}));
|
||||
@ -726,15 +715,13 @@ impl<'a> TraitDef<'a> {
|
||||
let self_type = cx.ty_path(path);
|
||||
|
||||
let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
|
||||
let attrs = thin_vec![attr];
|
||||
let opt_trait_ref = Some(trait_ref);
|
||||
|
||||
let mut a = vec![attr];
|
||||
a.extend(self.attributes.iter().cloned());
|
||||
|
||||
cx.item(
|
||||
self.span,
|
||||
Ident::empty(),
|
||||
a,
|
||||
attrs,
|
||||
ast::ItemKind::Impl(Box::new(ast::Impl {
|
||||
unsafety: ast::Unsafe::No,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
@ -1078,9 +1065,9 @@ impl<'a> MethodDef<'a> {
|
||||
let mut body = mk_body(cx, selflike_fields);
|
||||
|
||||
let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
|
||||
let use_ref_pat = is_packed && !always_copy;
|
||||
let by_ref = ByRef::from(is_packed && !always_copy);
|
||||
let patterns =
|
||||
trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat);
|
||||
trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref);
|
||||
|
||||
// Do the let-destructuring.
|
||||
let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
|
||||
@ -1262,13 +1249,13 @@ impl<'a> MethodDef<'a> {
|
||||
|
||||
let sp = variant.span.with_ctxt(trait_.span.ctxt());
|
||||
let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
|
||||
let use_ref_pat = false; // because enums can't be repr(packed)
|
||||
let by_ref = ByRef::No; // because enums can't be repr(packed)
|
||||
let mut subpats: Vec<_> = trait_.create_struct_patterns(
|
||||
cx,
|
||||
variant_path,
|
||||
&variant.data,
|
||||
&prefixes,
|
||||
use_ref_pat,
|
||||
by_ref,
|
||||
);
|
||||
|
||||
// `(VariantK, VariantK, ...)` or just `VariantK`.
|
||||
@ -1429,7 +1416,7 @@ impl<'a> TraitDef<'a> {
|
||||
struct_path: ast::Path,
|
||||
struct_def: &'a VariantData,
|
||||
prefixes: &[String],
|
||||
use_ref_pat: bool,
|
||||
by_ref: ByRef,
|
||||
) -> Vec<P<ast::Pat>> {
|
||||
prefixes
|
||||
.iter()
|
||||
@ -1437,17 +1424,19 @@ impl<'a> TraitDef<'a> {
|
||||
let pieces_iter =
|
||||
struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
|
||||
let sp = struct_field.span.with_ctxt(self.span.ctxt());
|
||||
let binding_mode = if use_ref_pat {
|
||||
ast::BindingMode::ByRef(ast::Mutability::Not)
|
||||
} else {
|
||||
ast::BindingMode::ByValue(ast::Mutability::Not)
|
||||
};
|
||||
let ident = self.mk_pattern_ident(prefix, i);
|
||||
let path = ident.with_span_pos(sp);
|
||||
(
|
||||
sp,
|
||||
struct_field.ident,
|
||||
cx.pat(path.span, PatKind::Ident(binding_mode, path, None)),
|
||||
cx.pat(
|
||||
path.span,
|
||||
PatKind::Ident(
|
||||
BindingAnnotation(by_ref, Mutability::Not),
|
||||
path,
|
||||
None,
|
||||
),
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
@ -1637,19 +1626,3 @@ where
|
||||
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the type has no value fields
|
||||
/// (for an enum, no variant has any fields)
|
||||
pub fn is_type_without_fields(item: &Annotatable) -> bool {
|
||||
if let Annotatable::Item(ref item) = *item {
|
||||
match item.kind {
|
||||
ast::ItemKind::Enum(ref enum_def, _) => {
|
||||
enum_def.variants.iter().all(|v| v.data.fields().is_empty())
|
||||
}
|
||||
ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(),
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,7 +146,6 @@ fn mk_ty_param(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
attrs: &[ast::Attribute],
|
||||
bounds: &[Path],
|
||||
self_ident: Ident,
|
||||
self_generics: &Generics,
|
||||
@ -158,7 +157,7 @@ fn mk_ty_param(
|
||||
cx.trait_bound(path)
|
||||
})
|
||||
.collect();
|
||||
cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
|
||||
cx.typaram(span, Ident::new(name, span), bounds, None)
|
||||
}
|
||||
|
||||
/// Bounds on type parameters.
|
||||
@ -183,7 +182,7 @@ impl Bounds {
|
||||
.iter()
|
||||
.map(|t| {
|
||||
let (name, ref bounds) = *t;
|
||||
mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
|
||||
mk_ty_param(cx, span, name, &bounds, self_ty, self_generics)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::{path_std, pathvec_std};
|
||||
|
||||
use rustc_ast::{MetaItem, Mutability};
|
||||
use rustc_ast::{AttrVec, MetaItem, Mutability};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
@ -21,7 +21,6 @@ pub fn expand_deriving_hash(
|
||||
let arg = Path::new_local(typaram);
|
||||
let hash_trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
path,
|
||||
additional_bounds: Vec::new(),
|
||||
generics: Bounds::empty(),
|
||||
@ -32,7 +31,7 @@ pub fn expand_deriving_hash(
|
||||
explicit_self: true,
|
||||
nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
|
||||
ret_ty: Unit,
|
||||
attributes: vec![],
|
||||
attributes: AttrVec::new(),
|
||||
unify_fieldless_variants: true,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
hash_substructure(a, b, c)
|
||||
|
||||
@ -164,7 +164,7 @@ fn inject_impl_of_structural_trait(
|
||||
|
||||
// Keep the lint and stability attributes of the original item, to control
|
||||
// how the generated implementation is linted.
|
||||
let mut attrs = Vec::new();
|
||||
let mut attrs = ast::AttrVec::new();
|
||||
attrs.extend(
|
||||
item.attrs
|
||||
.iter()
|
||||
|
||||
@ -48,7 +48,7 @@ fn expand<'cx>(
|
||||
MacEager::expr(
|
||||
cx.expr(
|
||||
sp,
|
||||
ExprKind::MacCall(MacCall {
|
||||
ExprKind::MacCall(P(MacCall {
|
||||
path: Path {
|
||||
span: sp,
|
||||
segments: cx
|
||||
@ -64,7 +64,7 @@ fn expand<'cx>(
|
||||
tts,
|
||||
)),
|
||||
prior_type_ascription: None,
|
||||
}),
|
||||
})),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@ -130,64 +130,46 @@ impl PositionalNamedArgsLint {
|
||||
/// CountIsParam, which contains an index into the arguments.
|
||||
fn maybe_add_positional_named_arg(
|
||||
&mut self,
|
||||
current_positional_arg: usize,
|
||||
total_args_length: usize,
|
||||
format_argument_index: usize,
|
||||
arg: Option<&FormatArg>,
|
||||
ty: PositionalNamedArgType,
|
||||
cur_piece: usize,
|
||||
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
|
||||
names: &FxHashMap<Symbol, (usize, Span)>,
|
||||
has_formatting: bool,
|
||||
) {
|
||||
let start_of_named_args = total_args_length - names.len();
|
||||
if current_positional_arg >= start_of_named_args {
|
||||
self.maybe_push(
|
||||
format_argument_index,
|
||||
ty,
|
||||
cur_piece,
|
||||
inner_span_to_replace,
|
||||
names,
|
||||
has_formatting,
|
||||
)
|
||||
if let Some(arg) = arg {
|
||||
if let Some(name) = arg.name {
|
||||
self.push(name, ty, cur_piece, inner_span_to_replace, has_formatting)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional
|
||||
/// named arguments. If a named arg associated with `format_argument_index` cannot be found,
|
||||
/// a new item will not be added as the lint cannot be emitted in this case.
|
||||
fn maybe_push(
|
||||
/// Construct a PositionalNamedArg struct and push it into the vec of positional
|
||||
/// named arguments.
|
||||
fn push(
|
||||
&mut self,
|
||||
format_argument_index: usize,
|
||||
arg_name: Ident,
|
||||
ty: PositionalNamedArgType,
|
||||
cur_piece: usize,
|
||||
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
|
||||
names: &FxHashMap<Symbol, (usize, Span)>,
|
||||
has_formatting: bool,
|
||||
) {
|
||||
let named_arg = names
|
||||
.iter()
|
||||
.find(|&(_, &(index, _))| index == format_argument_index)
|
||||
.map(|found| found.clone());
|
||||
|
||||
if let Some((&replacement, &(_, positional_named_arg_span))) = named_arg {
|
||||
// In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
|
||||
// the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
|
||||
// `Precision`.
|
||||
let inner_span_to_replace = if ty == PositionalNamedArgType::Precision {
|
||||
inner_span_to_replace
|
||||
.map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end })
|
||||
} else {
|
||||
inner_span_to_replace
|
||||
};
|
||||
self.positional_named_args.push(PositionalNamedArg {
|
||||
ty,
|
||||
cur_piece,
|
||||
inner_span_to_replace,
|
||||
replacement,
|
||||
positional_named_arg_span,
|
||||
has_formatting,
|
||||
});
|
||||
}
|
||||
// In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
|
||||
// the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
|
||||
// `Precision`.
|
||||
let inner_span_to_replace = if ty == PositionalNamedArgType::Precision {
|
||||
inner_span_to_replace
|
||||
.map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end })
|
||||
} else {
|
||||
inner_span_to_replace
|
||||
};
|
||||
self.positional_named_args.push(PositionalNamedArg {
|
||||
ty,
|
||||
cur_piece,
|
||||
inner_span_to_replace,
|
||||
replacement: arg_name.name,
|
||||
positional_named_arg_span: arg_name.span,
|
||||
has_formatting,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,7 +193,7 @@ struct Context<'a, 'b> {
|
||||
/// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]`
|
||||
/// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
|
||||
/// * `names` (in JSON): `{"foo": 2}`
|
||||
args: Vec<P<ast::Expr>>,
|
||||
args: Vec<FormatArg>,
|
||||
/// The number of arguments that were added by implicit capturing.
|
||||
num_captured_args: usize,
|
||||
/// Placeholder slot numbers indexed by argument.
|
||||
@ -219,7 +201,7 @@ struct Context<'a, 'b> {
|
||||
/// Unique format specs seen for each argument.
|
||||
arg_unique_types: Vec<Vec<ArgumentType>>,
|
||||
/// Map from named arguments to their resolved indices.
|
||||
names: FxHashMap<Symbol, (usize, Span)>,
|
||||
names: FxHashMap<Symbol, usize>,
|
||||
|
||||
/// The latest consecutive literal strings, or empty if there weren't any.
|
||||
literal: String,
|
||||
@ -282,7 +264,7 @@ struct Context<'a, 'b> {
|
||||
|
||||
pub struct FormatArg {
|
||||
expr: P<ast::Expr>,
|
||||
named: bool,
|
||||
name: Option<Ident>,
|
||||
}
|
||||
|
||||
/// Parses the arguments from the given list of tokens, returning the diagnostic
|
||||
@ -298,9 +280,9 @@ fn parse_args<'a>(
|
||||
ecx: &mut ExtCtxt<'a>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, (usize, Span)>)> {
|
||||
) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, usize>)> {
|
||||
let mut args = Vec::<FormatArg>::new();
|
||||
let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
|
||||
let mut names = FxHashMap::<Symbol, usize>::default();
|
||||
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
|
||||
@ -365,9 +347,9 @@ fn parse_args<'a>(
|
||||
p.bump();
|
||||
p.expect(&token::Eq)?;
|
||||
let e = p.parse_expr()?;
|
||||
if let Some((prev, _)) = names.get(&ident.name) {
|
||||
if let Some(&prev) = names.get(&ident.name) {
|
||||
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
|
||||
.span_label(args[*prev].expr.span, "previously here")
|
||||
.span_label(args[prev].expr.span, "previously here")
|
||||
.span_label(e.span, "duplicate argument")
|
||||
.emit();
|
||||
continue;
|
||||
@ -378,8 +360,8 @@ fn parse_args<'a>(
|
||||
// if the input is valid, we can simply append to the positional
|
||||
// args. And remember the names.
|
||||
let slot = args.len();
|
||||
names.insert(ident.name, (slot, ident.span));
|
||||
args.push(FormatArg { expr: e, named: true });
|
||||
names.insert(ident.name, slot);
|
||||
args.push(FormatArg { expr: e, name: Some(ident) });
|
||||
}
|
||||
_ => {
|
||||
let e = p.parse_expr()?;
|
||||
@ -389,12 +371,12 @@ fn parse_args<'a>(
|
||||
"positional arguments cannot follow named arguments",
|
||||
);
|
||||
err.span_label(e.span, "positional arguments must be before named arguments");
|
||||
for pos in names.values() {
|
||||
err.span_label(args[pos.0].expr.span, "named argument");
|
||||
for &pos in names.values() {
|
||||
err.span_label(args[pos].expr.span, "named argument");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
args.push(FormatArg { expr: e, named: false });
|
||||
args.push(FormatArg { expr: e, name: None });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -410,8 +392,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) {
|
||||
// NOTE: the `unwrap_or` branch is needed in case of invalid format
|
||||
// arguments, e.g., `format_args!("{foo}")`.
|
||||
let lookup =
|
||||
|s: &str| self.names.get(&Symbol::intern(s)).unwrap_or(&(0, Span::default())).0;
|
||||
let lookup = |s: &str| self.names.get(&Symbol::intern(s)).copied().unwrap_or(0);
|
||||
|
||||
match *p {
|
||||
parse::String(_) => {}
|
||||
@ -432,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
/// Verifies one piece of a parse string, and remembers it if valid.
|
||||
/// All errors are not emitted as fatal so we can continue giving errors
|
||||
/// about this and possibly other format strings.
|
||||
fn verify_piece(&mut self, p: &parse::Piece<'_>) {
|
||||
fn verify_piece(&mut self, p: &parse::Piece<'a>) {
|
||||
match *p {
|
||||
parse::String(..) => {}
|
||||
parse::NextArgument(ref arg) => {
|
||||
@ -452,18 +433,20 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
let has_precision = arg.format.precision != Count::CountImplied;
|
||||
let has_width = arg.format.width != Count::CountImplied;
|
||||
|
||||
if has_precision || has_width {
|
||||
// push before named params are resolved to aid diagnostics
|
||||
self.arg_with_formatting.push(arg.format);
|
||||
}
|
||||
|
||||
// argument second, if it's an implicit positional parameter
|
||||
// it's written second, so it should come after width/precision.
|
||||
let pos = match arg.position {
|
||||
parse::ArgumentIs(i) => {
|
||||
self.unused_names_lint.maybe_add_positional_named_arg(
|
||||
i,
|
||||
self.args.len(),
|
||||
i,
|
||||
self.args.get(i),
|
||||
PositionalNamedArgType::Arg,
|
||||
self.curpiece,
|
||||
Some(arg.position_span),
|
||||
&self.names,
|
||||
has_precision || has_width,
|
||||
);
|
||||
|
||||
@ -471,13 +454,10 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
}
|
||||
parse::ArgumentImplicitlyIs(i) => {
|
||||
self.unused_names_lint.maybe_add_positional_named_arg(
|
||||
i,
|
||||
self.args.len(),
|
||||
i,
|
||||
self.args.get(i),
|
||||
PositionalNamedArgType::Arg,
|
||||
self.curpiece,
|
||||
None,
|
||||
&self.names,
|
||||
has_precision || has_width,
|
||||
);
|
||||
Exact(i)
|
||||
@ -561,15 +541,12 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
) {
|
||||
match c {
|
||||
parse::CountImplied | parse::CountIs(..) => {}
|
||||
parse::CountIsParam(i) => {
|
||||
parse::CountIsParam(i) | parse::CountIsStar(i) => {
|
||||
self.unused_names_lint.maybe_add_positional_named_arg(
|
||||
i,
|
||||
self.args.len(),
|
||||
i,
|
||||
self.args.get(i),
|
||||
named_arg_type,
|
||||
self.curpiece,
|
||||
*inner_span,
|
||||
&self.names,
|
||||
true,
|
||||
);
|
||||
self.verify_arg_type(Exact(i), Count);
|
||||
@ -609,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
let mut zero_based_note = false;
|
||||
|
||||
let count = self.pieces.len()
|
||||
+ self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
|
||||
+ self
|
||||
.arg_with_formatting
|
||||
.iter()
|
||||
.filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
|
||||
.count();
|
||||
if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
|
||||
e = self.ecx.struct_span_err(
|
||||
sp,
|
||||
@ -622,7 +603,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
);
|
||||
for arg in &self.args {
|
||||
// Point at the arguments that will be formatted.
|
||||
e.span_label(arg.span, "");
|
||||
e.span_label(arg.expr.span, "");
|
||||
}
|
||||
} else {
|
||||
let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip();
|
||||
@ -658,7 +639,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
if let Some(span) = fmt.precision_span {
|
||||
let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
|
||||
match fmt.precision {
|
||||
parse::CountIsParam(pos) if pos > self.num_args() => {
|
||||
parse::CountIsParam(pos) if pos >= self.num_args() => {
|
||||
e.span_label(
|
||||
span,
|
||||
&format!(
|
||||
@ -670,12 +651,12 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
);
|
||||
zero_based_note = true;
|
||||
}
|
||||
parse::CountIsParam(pos) => {
|
||||
parse::CountIsStar(pos) => {
|
||||
let count = self.pieces.len()
|
||||
+ self
|
||||
.arg_with_formatting
|
||||
.iter()
|
||||
.filter(|fmt| fmt.precision_span.is_some())
|
||||
.filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
|
||||
.count();
|
||||
e.span_label(
|
||||
span,
|
||||
@ -692,7 +673,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
);
|
||||
if let Some(arg) = self.args.get(pos) {
|
||||
e.span_label(
|
||||
arg.span,
|
||||
arg.expr.span,
|
||||
"this parameter corresponds to the precision flag",
|
||||
);
|
||||
}
|
||||
@ -771,7 +752,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
match self.names.get(&name) {
|
||||
Some(&idx) => {
|
||||
// Treat as positional arg.
|
||||
self.verify_arg_type(Capture(idx.0), ty)
|
||||
self.verify_arg_type(Capture(idx), ty)
|
||||
}
|
||||
None => {
|
||||
// For the moment capturing variables from format strings expanded from macros is
|
||||
@ -787,8 +768,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
self.fmtsp
|
||||
};
|
||||
self.num_captured_args += 1;
|
||||
self.args.push(self.ecx.expr_ident(span, Ident::new(name, span)));
|
||||
self.names.insert(name, (idx, span));
|
||||
self.args.push(FormatArg {
|
||||
expr: self.ecx.expr_ident(span, Ident::new(name, span)),
|
||||
name: Some(Ident::new(name, span)),
|
||||
});
|
||||
self.names.insert(name, idx);
|
||||
self.verify_arg_type(Capture(idx), ty)
|
||||
} else {
|
||||
let msg = format!("there is no argument named `{}`", name);
|
||||
@ -853,7 +837,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
};
|
||||
match c {
|
||||
parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
|
||||
parse::CountIsParam(i) => {
|
||||
parse::CountIsParam(i) | parse::CountIsStar(i) => {
|
||||
// This needs mapping too, as `i` is referring to a macro
|
||||
// argument. If `i` is not found in `count_positions` then
|
||||
// the error had already been emitted elsewhere.
|
||||
@ -924,31 +908,27 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
},
|
||||
position_span: arg.position_span,
|
||||
format: parse::FormatSpec {
|
||||
fill: arg.format.fill,
|
||||
fill: None,
|
||||
align: parse::AlignUnknown,
|
||||
flags: 0,
|
||||
precision: parse::CountImplied,
|
||||
precision_span: None,
|
||||
precision_span: arg.format.precision_span,
|
||||
width: parse::CountImplied,
|
||||
width_span: None,
|
||||
width_span: arg.format.width_span,
|
||||
ty: arg.format.ty,
|
||||
ty_span: arg.format.ty_span,
|
||||
},
|
||||
};
|
||||
|
||||
let fill = arg.format.fill.unwrap_or(' ');
|
||||
|
||||
let pos_simple = arg.position.index() == simple_arg.position.index();
|
||||
|
||||
if arg.format.precision_span.is_some() || arg.format.width_span.is_some() {
|
||||
self.arg_with_formatting.push(arg.format);
|
||||
}
|
||||
if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
|
||||
if !pos_simple || arg.format != simple_arg.format {
|
||||
self.all_pieces_simple = false;
|
||||
}
|
||||
|
||||
// Build the format
|
||||
let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
|
||||
let fill = self.ecx.expr_char(sp, fill);
|
||||
let align = |name| {
|
||||
let mut p = Context::rtpath(self.ecx, sym::Alignment);
|
||||
p.push(Ident::new(name, sp));
|
||||
@ -1054,11 +1034,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
// evaluated a single time each, in the order written by the programmer,
|
||||
// and that the surrounding future/generator (if any) is Send whenever
|
||||
// possible.
|
||||
let no_need_for_match =
|
||||
nicely_ordered && !original_args.iter().skip(1).any(|e| may_contain_yield_point(e));
|
||||
let no_need_for_match = nicely_ordered
|
||||
&& !original_args.iter().skip(1).any(|arg| may_contain_yield_point(&arg.expr));
|
||||
|
||||
for (arg_index, arg_ty) in fmt_arg_index_and_ty {
|
||||
let e = &mut original_args[arg_index];
|
||||
let e = &mut original_args[arg_index].expr;
|
||||
let span = e.span;
|
||||
let arg = if no_need_for_match {
|
||||
let expansion_span = e.span.with_ctxt(self.macsp.ctxt());
|
||||
@ -1087,7 +1067,9 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
// span is otherwise unavailable in the MIR used by borrowck).
|
||||
let heads = original_args
|
||||
.into_iter()
|
||||
.map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e))
|
||||
.map(|arg| {
|
||||
self.ecx.expr_addr_of(arg.expr.span.with_ctxt(self.macsp.ctxt()), arg.expr)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
|
||||
@ -1199,7 +1181,7 @@ fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>)
|
||||
|
||||
cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
|
||||
span: MultiSpan::from_span(named_arg.positional_named_arg_span),
|
||||
msg: msg.clone(),
|
||||
msg: msg.into(),
|
||||
node_id: ast::CRATE_NODE_ID,
|
||||
lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
|
||||
diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
|
||||
@ -1220,7 +1202,7 @@ pub fn expand_preparsed_format_args(
|
||||
sp: Span,
|
||||
efmt: P<ast::Expr>,
|
||||
args: Vec<FormatArg>,
|
||||
names: FxHashMap<Symbol, (usize, Span)>,
|
||||
names: FxHashMap<Symbol, usize>,
|
||||
append_newline: bool,
|
||||
) -> P<ast::Expr> {
|
||||
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
|
||||
@ -1312,16 +1294,17 @@ pub fn expand_preparsed_format_args(
|
||||
if err.should_be_replaced_with_positional_argument {
|
||||
let captured_arg_span =
|
||||
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
|
||||
let positional_args = args.iter().filter(|arg| !arg.named).collect::<Vec<_>>();
|
||||
let n_positional_args =
|
||||
args.iter().rposition(|arg| arg.name.is_none()).map_or(0, |i| i + 1);
|
||||
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
|
||||
let span = match positional_args.last() {
|
||||
let span = match args[..n_positional_args].last() {
|
||||
Some(arg) => arg.expr.span,
|
||||
None => fmt_sp,
|
||||
};
|
||||
e.multipart_suggestion_verbose(
|
||||
"consider using a positional formatting argument instead",
|
||||
vec![
|
||||
(captured_arg_span, positional_args.len().to_string()),
|
||||
(captured_arg_span, n_positional_args.to_string()),
|
||||
(span.shrink_to_hi(), format!(", {}", arg)),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
@ -1338,11 +1321,9 @@ pub fn expand_preparsed_format_args(
|
||||
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
|
||||
.collect();
|
||||
|
||||
let named_pos: FxHashSet<usize> = names.values().cloned().map(|(i, _)| i).collect();
|
||||
|
||||
let mut cx = Context {
|
||||
ecx,
|
||||
args: args.into_iter().map(|arg| arg.expr).collect(),
|
||||
args,
|
||||
num_captured_args: 0,
|
||||
arg_types,
|
||||
arg_unique_types,
|
||||
@ -1410,14 +1391,12 @@ pub fn expand_preparsed_format_args(
|
||||
.enumerate()
|
||||
.filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
|
||||
.map(|(i, _)| {
|
||||
let msg = if named_pos.contains(&i) {
|
||||
// named argument
|
||||
let msg = if cx.args[i].name.is_some() {
|
||||
"named argument never used"
|
||||
} else {
|
||||
// positional argument
|
||||
"argument never used"
|
||||
};
|
||||
(cx.args[i].span, msg)
|
||||
(cx.args[i].expr.span, msg)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
||||
@ -4,11 +4,12 @@ use rustc_ast::expand::allocator::{
|
||||
AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
|
||||
};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
|
||||
use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
|
||||
use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn expand(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
@ -113,10 +114,10 @@ impl AllocFnFactory<'_, '_> {
|
||||
self.cx.expr_call(self.ty_span, method, args)
|
||||
}
|
||||
|
||||
fn attrs(&self) -> Vec<Attribute> {
|
||||
fn attrs(&self) -> AttrVec {
|
||||
let special = sym::rustc_std_internal_symbol;
|
||||
let special = self.cx.meta_word(self.span, special);
|
||||
vec![self.cx.attribute(special)]
|
||||
thin_vec![self.cx.attribute(special)]
|
||||
}
|
||||
|
||||
fn arg_ty(
|
||||
|
||||
@ -9,13 +9,16 @@
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(is_sorted)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![cfg_attr(bootstrap, feature(let_else))]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
use crate::deriving::*;
|
||||
|
||||
use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
|
||||
|
||||
@ -281,7 +281,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
|
||||
let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
|
||||
|
||||
let proc_macro = Ident::new(sym::proc_macro, span);
|
||||
let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None));
|
||||
let krate = cx.item(span, proc_macro, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None));
|
||||
|
||||
let bridge = Ident::new(sym::bridge, span);
|
||||
let client = Ident::new(sym::client, span);
|
||||
|
||||
@ -216,7 +216,7 @@ pub fn expand_include_bytes(
|
||||
}
|
||||
};
|
||||
match cx.source_map().load_binary_file(&file) {
|
||||
Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(bytes.into()))),
|
||||
Ok(bytes) => base::MacEager::expr(cx.expr_byte_str(sp, bytes)),
|
||||
Err(e) => {
|
||||
cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
|
||||
DummyResult::any(sp)
|
||||
|
||||
@ -6,6 +6,7 @@ use rustc_span::edition::Edition::*;
|
||||
use rustc_span::hygiene::AstPass;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn inject(
|
||||
mut krate: ast::Crate,
|
||||
@ -51,7 +52,7 @@ pub fn inject(
|
||||
cx.item(
|
||||
span,
|
||||
ident,
|
||||
vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
|
||||
thin_vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
|
||||
ast::ItemKind::ExternCrate(None),
|
||||
),
|
||||
);
|
||||
@ -78,7 +79,7 @@ pub fn inject(
|
||||
let use_item = cx.item(
|
||||
span,
|
||||
Ident::empty(),
|
||||
vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
|
||||
thin_vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
|
||||
ast::ItemKind::Use(ast::UseTree {
|
||||
prefix: cx.path(span, import_path),
|
||||
kind: ast::UseTreeKind::Glob,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
/// The expansion from a test function to the appropriate test struct for libtest
|
||||
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
|
||||
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::attr;
|
||||
use rustc_ast::ptr::P;
|
||||
@ -11,8 +10,8 @@ use rustc_expand::base::*;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::iter;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
// #[test_case] is used by custom test authors to mark tests
|
||||
// When building for test, it needs to make the item public and gensym the name
|
||||
@ -219,7 +218,7 @@ pub fn expand_test_or_bench(
|
||||
let mut test_const = cx.item(
|
||||
sp,
|
||||
Ident::new(item.ident.name, sp),
|
||||
vec![
|
||||
thin_vec![
|
||||
// #[cfg(test)]
|
||||
cx.attribute(attr::mk_list_item(
|
||||
Ident::new(sym::cfg, attr_sp),
|
||||
@ -334,9 +333,9 @@ pub fn expand_test_or_bench(
|
||||
});
|
||||
|
||||
// extern crate test
|
||||
let test_extern = cx.item(sp, test_id, vec![], ast::ItemKind::ExternCrate(None));
|
||||
let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None));
|
||||
|
||||
tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
|
||||
debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
|
||||
|
||||
if is_stmt {
|
||||
vec![
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user