Merge from rust-lang/rust
This commit is contained in:
commit
9d2bb7f40f
4746 changed files with 87513 additions and 51807 deletions
12
.github/pull_request_template.md
vendored
Normal file
12
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!-- homu-ignore:start -->
|
||||
<!--
|
||||
If this PR is related to an unstable feature or an otherwise tracked effort,
|
||||
please link to the relevant tracking issue here. If you don't know of a related
|
||||
tracking issue or there are none, feel free to ignore this.
|
||||
|
||||
This PR will get automatically assigned to a reviewer. In case you would like
|
||||
a specific user to review your work, you can assign it to them by using
|
||||
|
||||
r? <reviewer name>
|
||||
-->
|
||||
<!-- homu-ignore:end -->
|
||||
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
|
@ -38,6 +38,8 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
env:
|
||||
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
||||
# This will be empty in PR jobs.
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
jobs:
|
||||
# The job matrix for `calculate_matrix` is defined in src/ci/github-actions/jobs.yml.
|
||||
# It calculates which jobs should be executed, based on the data of the ${{ github }} context.
|
||||
|
|
@ -93,8 +95,6 @@ jobs:
|
|||
path-type: inherit
|
||||
install: >
|
||||
make
|
||||
dos2unix
|
||||
diffutils
|
||||
|
||||
- name: disable git crlf conversion
|
||||
run: git config --global core.autocrlf false
|
||||
|
|
@ -155,9 +155,6 @@ jobs:
|
|||
- name: checkout submodules
|
||||
run: src/ci/scripts/checkout-submodules.sh
|
||||
|
||||
- name: install MSYS2
|
||||
run: src/ci/scripts/install-msys2.sh
|
||||
|
||||
- name: install MinGW
|
||||
run: src/ci/scripts/install-mingw.sh
|
||||
|
||||
|
|
@ -190,7 +187,6 @@ jobs:
|
|||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
|
|
@ -240,4 +236,5 @@ jobs:
|
|||
shell: bash
|
||||
if: needs.calculate_matrix.outputs.run_type == 'auto'
|
||||
env:
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -52,6 +52,7 @@ build/
|
|||
/src/tools/x/target
|
||||
# Created by default with `src/ci/docker/run.sh`
|
||||
/obj/
|
||||
/rustc-ice*
|
||||
|
||||
## Temporary files
|
||||
*~
|
||||
|
|
|
|||
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -33,7 +33,7 @@
|
|||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/rust-lang/llvm-project.git
|
||||
branch = rustc/18.0-2024-02-13
|
||||
branch = rustc/18.1-2024-05-19
|
||||
shallow = true
|
||||
[submodule "src/doc/embedded-book"]
|
||||
path = src/doc/embedded-book
|
||||
|
|
@ -43,3 +43,7 @@
|
|||
path = library/backtrace
|
||||
url = https://github.com/rust-lang/backtrace-rs.git
|
||||
shallow = true
|
||||
[submodule "src/tools/rustc-perf"]
|
||||
path = src/tools/rustc-perf
|
||||
url = https://github.com/rust-lang/rustc-perf.git
|
||||
shallow = true
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -379,6 +379,7 @@ Markus Westerlind <marwes91@gmail.com> Markus <marwes91@gmail.com>
|
|||
Martin Carton <cartonmartin+git@gmail.com>
|
||||
Martin Habovštiak <martin.habovstiak@gmail.com>
|
||||
Martin Hafskjold Thoresen <martinhath@gmail.com>
|
||||
Martin Nordholts <martin.nordholts@codetale.se> <enselic@gmail.com>
|
||||
Matej Lach <matej.lach@gmail.com> Matej Ľach <matej.lach@gmail.com>
|
||||
Mateusz Mikuła <mati865@gmail.com>
|
||||
Mateusz Mikuła <mati865@gmail.com> <mati865@users.noreply.github.com>
|
||||
|
|
|
|||
1299
Cargo.lock
1299
Cargo.lock
File diff suppressed because it is too large
Load diff
|
|
@ -23,7 +23,6 @@ members = [
|
|||
"src/tools/remote-test-client",
|
||||
"src/tools/remote-test-server",
|
||||
"src/tools/rust-installer",
|
||||
"src/tools/rust-demangler",
|
||||
"src/tools/rustdoc",
|
||||
"src/tools/rls",
|
||||
"src/tools/rustfmt",
|
||||
|
|
|
|||
129
RELEASES.md
129
RELEASES.md
|
|
@ -1,3 +1,130 @@
|
|||
Version 1.79.0 (2024-06-13)
|
||||
==========================
|
||||
|
||||
<a id="1.79.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize inline `const {}` expressions.](https://github.com/rust-lang/rust/pull/104087/)
|
||||
- [Prevent opaque types being instantiated twice with different regions within the same function.](https://github.com/rust-lang/rust/pull/116935/)
|
||||
- [Stabilize WebAssembly target features that are in phase 4 and 5.](https://github.com/rust-lang/rust/pull/117457/)
|
||||
- [Add the `redundant_lifetimes` lint to detect lifetimes which are semantically redundant.](https://github.com/rust-lang/rust/pull/118391/)
|
||||
- [Stabilize the `unnameable_types` lint for public types that can't be named.](https://github.com/rust-lang/rust/pull/120144/)
|
||||
- [Enable debuginfo in macros, and stabilize `-C collapse-macro-debuginfo` and `#[collapse_debuginfo]`.](https://github.com/rust-lang/rust/pull/120845/)
|
||||
- [Propagate temporary lifetime extension into `if` and `match` expressions.](https://github.com/rust-lang/rust/pull/121346/)
|
||||
- [Restrict promotion of `const fn` calls.](https://github.com/rust-lang/rust/pull/121557/)
|
||||
- [Warn against refining impls of crate-private traits with `refining_impl_trait` lint.](https://github.com/rust-lang/rust/pull/121720/)
|
||||
- [Stabilize associated type bounds (RFC 2289).](https://github.com/rust-lang/rust/pull/122055/)
|
||||
- [Stabilize importing `main` from other modules or crates.](https://github.com/rust-lang/rust/pull/122060/)
|
||||
- [Check return types of function types for well-formedness](https://github.com/rust-lang/rust/pull/115538)
|
||||
- [Rework `impl Trait` lifetime inference](https://github.com/rust-lang/rust/pull/116891/)
|
||||
- [Change inductive trait solver cycles to be ambiguous](https://github.com/rust-lang/rust/pull/122791)
|
||||
|
||||
<a id="1.79.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Define `-C strip` to only affect binaries, not artifacts like `.pdb`.](https://github.com/rust-lang/rust/pull/115120/)
|
||||
- [Stabilize `-Crelro-level` for controlling runtime link hardening.](https://github.com/rust-lang/rust/pull/121694/)
|
||||
- [Stabilize checking of `cfg` names and values at compile-time with `--check-cfg`.](https://github.com/rust-lang/rust/pull/123501/)
|
||||
*Note that this only stabilizes the compiler part, the Cargo part is still unstable in this release.*
|
||||
- [Add `aarch64-apple-visionos` and `aarch64-apple-visionos-sim` tier 3 targets.](https://github.com/rust-lang/rust/pull/121419/)
|
||||
- [Add `riscv32ima-unknown-none-elf` tier 3 target.](https://github.com/rust-lang/rust/pull/122696/)
|
||||
- [Promote several Windows targets to tier 2](https://github.com/rust-lang/rust/pull/121712): `aarch64-pc-windows-gnullvm`, `i686-pc-windows-gnullvm`, and `x86_64-pc-windows-gnullvm`.
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.79.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [Implement `FromIterator` for `(impl Default + Extend, impl Default + Extend)`.](https://github.com/rust-lang/rust/pull/107462/)
|
||||
- [Implement `{Div,Rem}Assign<NonZero<X>>` on `X`.](https://github.com/rust-lang/rust/pull/121952/)
|
||||
- [Document overrides of `clone_from()` in core/std.](https://github.com/rust-lang/rust/pull/122201/)
|
||||
- [Link MSVC default lib in core.](https://github.com/rust-lang/rust/pull/122268/)
|
||||
- [Caution against using `transmute` between pointers and integers.](https://github.com/rust-lang/rust/pull/122379/)
|
||||
- [Enable frame pointers for the standard library.](https://github.com/rust-lang/rust/pull/122646/)
|
||||
|
||||
<a id="1.79.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`{integer}::unchecked_add`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_add)
|
||||
- [`{integer}::unchecked_mul`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_mul)
|
||||
- [`{integer}::unchecked_sub`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_sub)
|
||||
- [`<[T]>::split_at_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_unchecked)
|
||||
- [`<[T]>::split_at_mut_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut_unchecked)
|
||||
- [`<[u8]>::utf8_chunks`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.utf8_chunks)
|
||||
- [`str::Utf8Chunks`](https://doc.rust-lang.org/stable/core/str/struct.Utf8Chunks.html)
|
||||
- [`str::Utf8Chunk`](https://doc.rust-lang.org/stable/core/str/struct.Utf8Chunk.html)
|
||||
- [`<*const T>::is_aligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_aligned)
|
||||
- [`<*mut T>::is_aligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_aligned-1)
|
||||
- [`NonNull::is_aligned`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.is_aligned)
|
||||
- [`<*const [T]>::len`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.len)
|
||||
- [`<*mut [T]>::len`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.len-1)
|
||||
- [`<*const [T]>::is_empty`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_empty)
|
||||
- [`<*mut [T]>::is_empty`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_empty-1)
|
||||
- [`NonNull::<[T]>::is_empty`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.is_empty)
|
||||
- [`CStr::count_bytes`](https://doc.rust-lang.org/stable/core/ffi/c_str/struct.CStr.html#method.count_bytes)
|
||||
- [`io::Error::downcast`](https://doc.rust-lang.org/stable/std/io/struct.Error.html#method.downcast)
|
||||
- [`num::NonZero<T>`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html)
|
||||
- [`path::absolute`](https://doc.rust-lang.org/stable/std/path/fn.absolute.html)
|
||||
- [`proc_macro::Literal::byte_character`](https://doc.rust-lang.org/stable/proc_macro/struct.Literal.html#method.byte_character)
|
||||
- [`proc_macro::Literal::c_string`](https://doc.rust-lang.org/stable/proc_macro/struct.Literal.html#method.c_string)
|
||||
|
||||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`Atomic*::into_inner`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.into_inner)
|
||||
- [`io::Cursor::new`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.new)
|
||||
- [`io::Cursor::get_ref`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.get_ref)
|
||||
- [`io::Cursor::position`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.position)
|
||||
- [`io::empty`](https://doc.rust-lang.org/stable/std/io/fn.empty.html)
|
||||
- [`io::repeat`](https://doc.rust-lang.org/stable/std/io/fn.repeat.html)
|
||||
- [`io::sink`](https://doc.rust-lang.org/stable/std/io/fn.sink.html)
|
||||
- [`panic::Location::caller`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.caller)
|
||||
- [`panic::Location::file`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.file)
|
||||
- [`panic::Location::line`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.line)
|
||||
- [`panic::Location::column`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.column)
|
||||
|
||||
<a id="1.79.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- [Prevent dashes in `lib.name`, always normalizing to `_`.](https://github.com/rust-lang/cargo/pull/12783/)
|
||||
- [Stabilize MSRV-aware version requirement selection in `cargo add`.](https://github.com/rust-lang/cargo/pull/13608/)
|
||||
- [Switch to using `gitoxide` by default for listing files.](https://github.com/rust-lang/cargo/pull/13696/)
|
||||
|
||||
<a id="1.79.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
|
||||
- [Always display stability version even if it's the same as the containing item.](https://github.com/rust-lang/rust/pull/118441/)
|
||||
- [Show a single search result for items with multiple paths.](https://github.com/rust-lang/rust/pull/119912/)
|
||||
- [Support typing `/` in docs to begin a search.](https://github.com/rust-lang/rust/pull/123355/)
|
||||
|
||||
<a id="1.79.0-Misc"></a>
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
<a id="1.79.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- [Update the minimum external LLVM to 17.](https://github.com/rust-lang/rust/pull/122649/)
|
||||
- [`RustcEncodable` and `RustcDecodable` are soft-destabilized, to be removed
|
||||
from the prelude in next edition.](https://github.com/rust-lang/rust/pull/116016/)
|
||||
- [The `wasm_c_abi` future-incompatibility lint will warn about use of the
|
||||
non-spec-compliant C ABI.](https://github.com/rust-lang/rust/pull/117918/)
|
||||
Use `wasm-bindgen v0.2.88` to generate forward-compatible bindings.
|
||||
- [Check return types of function types for well-formedness](https://github.com/rust-lang/rust/pull/115538)
|
||||
|
||||
Version 1.78.0 (2024-05-02)
|
||||
==========================
|
||||
|
||||
|
|
@ -19,7 +146,7 @@ Language
|
|||
- [Split `refining_impl_trait` lint into `_reachable`, `_internal` variants](https://github.com/rust-lang/rust/pull/121720/)
|
||||
- [Remove unnecessary type inference when using associated types inside of higher ranked `where`-bounds](https://github.com/rust-lang/rust/pull/119849)
|
||||
- [Weaken eager detection of cyclic types during type inference](https://github.com/rust-lang/rust/pull/119989)
|
||||
- [`trait Trait: Auto {}`: allow upcasting from `dyn Trait` to `dyn Auto`](https://github.com/rust-lang/rust/pull/119338)
|
||||
- [`trait Trait: Auto {}`: allow upcasting from `dyn Trait` to `dyn Trait + Auto`](https://github.com/rust-lang/rust/pull/119338)
|
||||
|
||||
<a id="1.78.0-Compiler"></a>
|
||||
|
||||
|
|
|
|||
|
|
@ -970,7 +970,7 @@ fn univariant<
|
|||
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
|
||||
let mut max_repr_align = repr.align;
|
||||
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
|
||||
let optimize = !repr.inhibit_struct_field_reordering_opt();
|
||||
let optimize = !repr.inhibit_struct_field_reordering();
|
||||
if optimize && fields.len() > 1 {
|
||||
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
||||
let optimizing = &mut inverse_memory_index.raw[..end];
|
||||
|
|
@ -1007,13 +1007,15 @@ fn univariant<
|
|||
// Calculates a sort key to group fields by their alignment or possibly some
|
||||
// size-derived pseudo-alignment.
|
||||
let alignment_group_key = |layout: &F| {
|
||||
// The two branches here return values that cannot be meaningfully compared with
|
||||
// each other. However, we know that consistently for all executions of
|
||||
// `alignment_group_key`, one or the other branch will be taken, so this is okay.
|
||||
if let Some(pack) = pack {
|
||||
// Return the packed alignment in bytes.
|
||||
layout.align.abi.min(pack).bytes()
|
||||
} else {
|
||||
// Returns `log2(effective-align)`. This is ok since `pack` applies to all
|
||||
// fields equally. The calculation assumes that size is an integer multiple of
|
||||
// align, except for ZSTs.
|
||||
// Returns `log2(effective-align)`. The calculation assumes that size is an
|
||||
// integer multiple of align, except for ZSTs.
|
||||
let align = layout.align.abi.bytes();
|
||||
let size = layout.size.bytes();
|
||||
let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
#![cfg_attr(feature = "nightly", doc(rust_logo))]
|
||||
#![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
|
||||
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::fmt;
|
||||
use std::num::{NonZeroUsize, ParseIntError};
|
||||
|
|
@ -137,23 +139,16 @@ impl ReprOptions {
|
|||
self.c() || self.int.is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` should inhibit struct field reordering
|
||||
/// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr(<int>)`.
|
||||
pub fn inhibit_struct_field_reordering_opt(&self) -> bool {
|
||||
if let Some(pack) = self.pack {
|
||||
if pack.bytes() == 1 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` guarantees a fixed field order,
|
||||
/// e.g. `repr(C)` or `repr(<int>)`.
|
||||
pub fn inhibit_struct_field_reordering(&self) -> bool {
|
||||
self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
|
||||
/// was enabled for its declaration crate.
|
||||
pub fn can_randomize_type_layout(&self) -> bool {
|
||||
!self.inhibit_struct_field_reordering_opt()
|
||||
&& self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
|
||||
!self.inhibit_struct_field_reordering() && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
|
||||
|
|
|
|||
|
|
@ -7,23 +7,25 @@
|
|||
//!
|
||||
//! This crate implements several kinds of arena.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(clippy::mut_from_ref)] // Arena allocators are one place where this pattern is fine.
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![doc(
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
|
||||
test(no_crate_inject, attr(deny(warnings)))
|
||||
)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![allow(internal_features)]
|
||||
#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ impl PathSegment {
|
|||
}
|
||||
}
|
||||
|
||||
/// The arguments of a path segment.
|
||||
/// The generic arguments and associated item constraints of a path segment.
|
||||
///
|
||||
/// E.g., `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
|
|
@ -221,14 +221,13 @@ pub struct AngleBracketedArgs {
|
|||
pub args: ThinVec<AngleBracketedArg>,
|
||||
}
|
||||
|
||||
/// Either an argument for a parameter e.g., `'a`, `Vec<u8>`, `0`,
|
||||
/// or a constraint on an associated item, e.g., `Item = String` or `Item: Bound`.
|
||||
/// Either an argument for a generic parameter or a constraint on an associated item.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum AngleBracketedArg {
|
||||
/// Argument for a generic parameter.
|
||||
/// A generic argument for a generic parameter.
|
||||
Arg(GenericArg),
|
||||
/// Constraint for an associated item.
|
||||
Constraint(AssocConstraint),
|
||||
/// A constraint on an associated item.
|
||||
Constraint(AssocItemConstraint),
|
||||
}
|
||||
|
||||
impl AngleBracketedArg {
|
||||
|
|
@ -308,6 +307,8 @@ impl TraitBoundModifiers {
|
|||
pub enum GenericBound {
|
||||
Trait(PolyTraitRef, TraitBoundModifiers),
|
||||
Outlives(Lifetime),
|
||||
/// Precise capturing syntax: `impl Sized + use<'a>`
|
||||
Use(ThinVec<PreciseCapturingArg>, Span),
|
||||
}
|
||||
|
||||
impl GenericBound {
|
||||
|
|
@ -315,6 +316,7 @@ impl GenericBound {
|
|||
match self {
|
||||
GenericBound::Trait(t, ..) => t.span,
|
||||
GenericBound::Outlives(l) => l.ident.span,
|
||||
GenericBound::Use(_, span) => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -418,7 +420,7 @@ impl Default for WhereClause {
|
|||
/// A single predicate in a where-clause.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum WherePredicate {
|
||||
/// A type binding (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||
BoundPredicate(WhereBoundPredicate),
|
||||
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
|
||||
RegionPredicate(WhereRegionPredicate),
|
||||
|
|
@ -489,6 +491,7 @@ pub struct Crate {
|
|||
/// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct MetaItem {
|
||||
pub unsafety: Safety,
|
||||
pub path: Path,
|
||||
pub kind: MetaItemKind,
|
||||
pub span: Span,
|
||||
|
|
@ -972,7 +975,9 @@ impl UnOp {
|
|||
}
|
||||
}
|
||||
|
||||
/// A statement
|
||||
/// A statement. No `attrs` or `tokens` fields because each `StmtKind` variant
|
||||
/// contains an AST node with those fields. (Except for `StmtKind::Empty`,
|
||||
/// which never has attrs or tokens)
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Stmt {
|
||||
pub id: NodeId,
|
||||
|
|
@ -2034,18 +2039,25 @@ impl UintTy {
|
|||
}
|
||||
}
|
||||
|
||||
/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
|
||||
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
|
||||
/// A constraint on an associated item.
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
|
||||
/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
|
||||
/// * the `A: Bound` in `Trait<A: Bound>`
|
||||
/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
|
||||
/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
|
||||
/// * the `f(): Bound` in `Trait<f(): Bound>` (feature `return_type_notation`)
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct AssocConstraint {
|
||||
pub struct AssocItemConstraint {
|
||||
pub id: NodeId,
|
||||
pub ident: Ident,
|
||||
pub gen_args: Option<GenericArgs>,
|
||||
pub kind: AssocConstraintKind,
|
||||
pub kind: AssocItemConstraintKind,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// The kinds of an `AssocConstraint`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum Term {
|
||||
Ty(P<Ty>),
|
||||
|
|
@ -2064,12 +2076,17 @@ impl From<AnonConst> for Term {
|
|||
}
|
||||
}
|
||||
|
||||
/// The kinds of an `AssocConstraint`.
|
||||
/// The kind of [associated item constraint][AssocItemConstraint].
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum AssocConstraintKind {
|
||||
/// E.g., `A = Bar`, `A = 3` in `Foo<A = Bar>` where A is an associated type.
|
||||
pub enum AssocItemConstraintKind {
|
||||
/// An equality constraint for an associated item (e.g., `AssocTy = Ty` in `Trait<AssocTy = Ty>`).
|
||||
///
|
||||
/// Also known as an *associated item binding* (we *bind* an associated item to a term).
|
||||
///
|
||||
/// Furthermore, associated type equality constraints can also be referred to as *associated type
|
||||
/// bindings*. Similarly with associated const equality constraints and *associated const bindings*.
|
||||
Equality { term: Term },
|
||||
/// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
|
||||
/// A bound on an associated type (e.g., `AssocTy: Bound` in `Trait<AssocTy: Bound>`).
|
||||
Bound { bounds: GenericBounds },
|
||||
}
|
||||
|
||||
|
|
@ -2150,7 +2167,7 @@ pub enum TyKind {
|
|||
/// The `NodeId` exists to prevent lowering from having to
|
||||
/// generate `NodeId`s on the fly, which would complicate
|
||||
/// the generation of opaque `type Foo = impl Trait` items significantly.
|
||||
ImplTrait(NodeId, GenericBounds, Option<P<(ThinVec<PreciseCapturingArg>, Span)>>),
|
||||
ImplTrait(NodeId, GenericBounds),
|
||||
/// No-op; kept solely so that we can pretty-print faithfully.
|
||||
Paren(P<Ty>),
|
||||
/// Unused for now.
|
||||
|
|
@ -2490,6 +2507,8 @@ pub enum IsAuto {
|
|||
pub enum Safety {
|
||||
/// `unsafe` an item is explicitly marked as `unsafe`.
|
||||
Unsafe(Span),
|
||||
/// `safe` an item is explicitly marked as `safe`.
|
||||
Safe(Span),
|
||||
/// Default means no value was provided, it will take a default value given the context in
|
||||
/// which is used.
|
||||
Default,
|
||||
|
|
@ -2733,6 +2752,13 @@ pub enum UseTreeKind {
|
|||
/// `use prefix` or `use prefix as rename`
|
||||
Simple(Option<Ident>),
|
||||
/// `use prefix::{...}`
|
||||
///
|
||||
/// The span represents the braces of the nested group and all elements within:
|
||||
///
|
||||
/// ```text
|
||||
/// use foo::{bar, baz};
|
||||
/// ^^^^^^^^^^
|
||||
/// ```
|
||||
Nested { items: ThinVec<(UseTree, NodeId)>, span: Span },
|
||||
/// `use prefix::*`
|
||||
Glob,
|
||||
|
|
@ -2803,7 +2829,12 @@ pub struct NormalAttr {
|
|||
impl NormalAttr {
|
||||
pub fn from_ident(ident: Ident) -> Self {
|
||||
Self {
|
||||
item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None },
|
||||
item: AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(ident),
|
||||
args: AttrArgs::Empty,
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -2811,6 +2842,7 @@ impl NormalAttr {
|
|||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct AttrItem {
|
||||
pub unsafety: Safety,
|
||||
pub path: Path,
|
||||
pub args: AttrArgs,
|
||||
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
|
||||
|
|
@ -3131,19 +3163,23 @@ pub struct Delegation {
|
|||
pub path: Path,
|
||||
pub rename: Option<Ident>,
|
||||
pub body: Option<P<Block>>,
|
||||
/// The item was expanded from a glob delegation item.
|
||||
pub from_glob: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct DelegationMac {
|
||||
pub qself: Option<P<QSelf>>,
|
||||
pub prefix: Path,
|
||||
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
|
||||
// Some for list delegation, and None for glob delegation.
|
||||
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
|
||||
pub body: Option<P<Block>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct StaticItem {
|
||||
pub ty: P<Ty>,
|
||||
pub safety: Safety,
|
||||
pub mutability: Mutability,
|
||||
pub expr: Option<P<Expr>>,
|
||||
}
|
||||
|
|
@ -3153,6 +3189,7 @@ pub struct StaticItem {
|
|||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct StaticForeignItem {
|
||||
pub ty: P<Ty>,
|
||||
pub safety: Safety,
|
||||
pub mutability: Mutability,
|
||||
pub expr: Option<P<Expr>>,
|
||||
}
|
||||
|
|
@ -3161,6 +3198,7 @@ impl From<StaticItem> for StaticForeignItem {
|
|||
fn from(static_item: StaticItem) -> StaticForeignItem {
|
||||
StaticForeignItem {
|
||||
ty: static_item.ty,
|
||||
safety: static_item.safety,
|
||||
mutability: static_item.mutability,
|
||||
expr: static_item.expr,
|
||||
}
|
||||
|
|
@ -3171,6 +3209,7 @@ impl From<StaticForeignItem> for StaticItem {
|
|||
fn from(static_item: StaticForeignItem) -> StaticItem {
|
||||
StaticItem {
|
||||
ty: static_item.ty,
|
||||
safety: static_item.safety,
|
||||
mutability: static_item.mutability,
|
||||
expr: static_item.expr,
|
||||
}
|
||||
|
|
@ -3260,7 +3299,7 @@ pub enum ItemKind {
|
|||
///
|
||||
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
|
||||
Delegation(Box<Delegation>),
|
||||
/// A list delegation item (`reuse prefix::{a, b, c}`).
|
||||
/// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`).
|
||||
/// Treated similarly to a macro call and expanded early.
|
||||
DelegationMac(Box<DelegationMac>),
|
||||
}
|
||||
|
|
@ -3341,7 +3380,7 @@ pub enum AssocItemKind {
|
|||
MacCall(P<MacCall>),
|
||||
/// An associated delegation item.
|
||||
Delegation(Box<Delegation>),
|
||||
/// An associated delegation item list.
|
||||
/// An associated list or glob delegation item.
|
||||
DelegationMac(Box<DelegationMac>),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
//! Functions dealing with attributes and meta items.
|
||||
|
||||
use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
|
||||
use crate::ast::{
|
||||
AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Safety,
|
||||
};
|
||||
use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
|
||||
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
|
||||
use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
|
||||
|
|
@ -13,6 +15,7 @@ use crate::util::literal::escape_string_symbol;
|
|||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::iter;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
|
@ -87,10 +90,20 @@ impl Attribute {
|
|||
AttrKind::DocComment(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
}
|
||||
|
||||
pub fn path(&self) -> SmallVec<[Symbol; 1]> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
normal.item.path.segments.iter().map(|s| s.ident.name).collect()
|
||||
}
|
||||
AttrKind::DocComment(..) => smallvec![sym::doc],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_name(&self, name: Symbol) -> bool {
|
||||
match &self.kind {
|
||||
|
|
@ -227,7 +240,12 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta(&self, span: Span) -> Option<MetaItem> {
|
||||
Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
|
||||
Some(MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: self.path.clone(),
|
||||
kind: self.meta_kind()?,
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
||||
|
|
@ -360,7 +378,10 @@ impl MetaItem {
|
|||
_ => path.span.hi(),
|
||||
};
|
||||
let span = path.span.with_hi(hi);
|
||||
Some(MetaItem { path, kind, span })
|
||||
// FIXME: This parses `unsafe()` not as unsafe attribute syntax in `MetaItem`,
|
||||
// but as a parenthesized list. This (and likely `MetaItem`) should be changed in
|
||||
// such a way that builtin macros don't accept extraneous `unsafe()`.
|
||||
Some(MetaItem { unsafety: Safety::Default, path, kind, span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -544,11 +565,12 @@ pub fn mk_doc_comment(
|
|||
pub fn mk_attr(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
path: Path,
|
||||
args: AttrArgs,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
|
||||
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_from_item(
|
||||
|
|
@ -566,15 +588,22 @@ pub fn mk_attr_from_item(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
|
||||
pub fn mk_attr_word(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
let path = Path::from_ident(Ident::new(name, span));
|
||||
let args = AttrArgs::Empty;
|
||||
mk_attr(g, style, path, args, span)
|
||||
mk_attr(g, style, unsafety, path, args, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_nested_word(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
outer: Symbol,
|
||||
inner: Symbol,
|
||||
span: Span,
|
||||
|
|
@ -590,12 +619,13 @@ pub fn mk_attr_nested_word(
|
|||
delim: Delimiter::Parenthesis,
|
||||
tokens: inner_tokens,
|
||||
});
|
||||
mk_attr(g, style, path, attr_args, span)
|
||||
mk_attr(g, style, unsafety, path, attr_args, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_name_value_str(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
name: Symbol,
|
||||
val: Symbol,
|
||||
span: Span,
|
||||
|
|
@ -610,7 +640,7 @@ pub fn mk_attr_name_value_str(
|
|||
});
|
||||
let path = Path::from_ident(Ident::new(name, span));
|
||||
let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
|
||||
mk_attr(g, style, path, args, span)
|
||||
mk_attr(g, style, unsafety, path, args, span)
|
||||
}
|
||||
|
||||
pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
|
||||
|
|
|
|||
|
|
@ -4,20 +4,22 @@
|
|||
//!
|
||||
//! This API is completely unstable and subject to change.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![doc(
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
|
||||
test(attr(deny(warnings)))
|
||||
)]
|
||||
#![doc(rust_logo)]
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub mod util {
|
||||
pub mod case;
|
||||
|
|
|
|||
|
|
@ -175,8 +175,8 @@ pub trait MutVisitor: Sized {
|
|||
noop_visit_lifetime(l, self);
|
||||
}
|
||||
|
||||
fn visit_constraint(&mut self, t: &mut AssocConstraint) {
|
||||
noop_visit_constraint(t, self);
|
||||
fn visit_assoc_item_constraint(&mut self, c: &mut AssocItemConstraint) {
|
||||
noop_visit_assoc_item_constraint(c, self);
|
||||
}
|
||||
|
||||
fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
|
||||
|
|
@ -463,8 +463,8 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
|
|||
smallvec![arm]
|
||||
}
|
||||
|
||||
fn noop_visit_constraint<T: MutVisitor>(
|
||||
AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
|
||||
fn noop_visit_assoc_item_constraint<T: MutVisitor>(
|
||||
AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint,
|
||||
vis: &mut T,
|
||||
) {
|
||||
vis.visit_id(id);
|
||||
|
|
@ -473,11 +473,11 @@ fn noop_visit_constraint<T: MutVisitor>(
|
|||
vis.visit_generic_args(gen_args);
|
||||
}
|
||||
match kind {
|
||||
AssocConstraintKind::Equality { term } => match term {
|
||||
AssocItemConstraintKind::Equality { term } => match term {
|
||||
Term::Ty(ty) => vis.visit_ty(ty),
|
||||
Term::Const(c) => vis.visit_anon_const(c),
|
||||
},
|
||||
AssocConstraintKind::Bound { bounds } => visit_bounds(bounds, vis),
|
||||
AssocItemConstraintKind::Bound { bounds } => visit_bounds(bounds, vis),
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
|
@ -523,14 +523,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
|||
TyKind::TraitObject(bounds, _syntax) => {
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound))
|
||||
}
|
||||
TyKind::ImplTrait(id, bounds, precise_capturing) => {
|
||||
TyKind::ImplTrait(id, bounds) => {
|
||||
vis.visit_id(id);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
||||
if let Some((precise_capturing, _span)) = precise_capturing.as_deref_mut() {
|
||||
for arg in precise_capturing {
|
||||
vis.visit_precise_capturing_arg(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
|
||||
|
|
@ -607,7 +602,7 @@ fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
|
|||
let AngleBracketedArgs { args, span } = data;
|
||||
visit_thin_vec(args, |arg| match arg {
|
||||
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
|
||||
AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint),
|
||||
AngleBracketedArg::Constraint(constraint) => vis.visit_assoc_item_constraint(constraint),
|
||||
});
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
|
@ -647,8 +642,10 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
|
|||
let Attribute { kind, id: _, style: _, span } = attr;
|
||||
match kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } =
|
||||
&mut **normal;
|
||||
let NormalAttr {
|
||||
item: AttrItem { unsafety: _, path, args, tokens },
|
||||
tokens: attr_tokens,
|
||||
} = &mut **normal;
|
||||
vis.visit_path(path);
|
||||
visit_attr_args(args, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
|
|
@ -678,7 +675,7 @@ fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T
|
|||
}
|
||||
|
||||
fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
|
||||
let MetaItem { path: _, kind, span } = mi;
|
||||
let MetaItem { unsafety: _, path: _, kind, span } = mi;
|
||||
match kind {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)),
|
||||
|
|
@ -840,7 +837,7 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
|
|||
token::NtTy(ty) => vis.visit_ty(ty),
|
||||
token::NtLiteral(expr) => vis.visit_expr(expr),
|
||||
token::NtMeta(item) => {
|
||||
let AttrItem { path, args, tokens } = item.deref_mut();
|
||||
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
|
||||
vis.visit_path(path);
|
||||
visit_attr_args(args, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
|
|
@ -862,6 +859,7 @@ fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T)
|
|||
fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) {
|
||||
match safety {
|
||||
Safety::Unsafe(span) => vis.visit_span(span),
|
||||
Safety::Safe(span) => vis.visit_span(span),
|
||||
Safety::Default => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -920,6 +918,11 @@ fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) {
|
|||
match pb {
|
||||
GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty),
|
||||
GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis),
|
||||
GenericBound::Use(args, _) => {
|
||||
for arg in args {
|
||||
vis.visit_precise_capturing_arg(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1079,7 +1082,7 @@ impl NoopVisitItemKind for ItemKind {
|
|||
match self {
|
||||
ItemKind::ExternCrate(_orig_name) => {}
|
||||
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
||||
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
|
||||
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
||||
vis.visit_ty(ty);
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
|
|
@ -1159,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind {
|
|||
}
|
||||
ItemKind::MacCall(m) => vis.visit_mac_call(m),
|
||||
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
|
||||
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
|
||||
ItemKind::Delegation(box Delegation {
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
rename,
|
||||
body,
|
||||
from_glob: _,
|
||||
}) => {
|
||||
vis.visit_id(id);
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
|
|
@ -1173,10 +1183,12 @@ impl NoopVisitItemKind for ItemKind {
|
|||
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(prefix);
|
||||
for (ident, rename) in suffixes {
|
||||
vis.visit_ident(ident);
|
||||
if let Some(rename) = rename {
|
||||
vis.visit_ident(rename);
|
||||
if let Some(suffixes) = suffixes {
|
||||
for (ident, rename) in suffixes {
|
||||
vis.visit_ident(ident);
|
||||
if let Some(rename) = rename {
|
||||
vis.visit_ident(rename);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(body) = body {
|
||||
|
|
@ -1215,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind {
|
|||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
}
|
||||
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
|
||||
AssocItemKind::Delegation(box Delegation {
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
rename,
|
||||
body,
|
||||
from_glob: _,
|
||||
}) => {
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_qself(qself);
|
||||
visitor.visit_path(path);
|
||||
|
|
@ -1229,10 +1248,12 @@ impl NoopVisitItemKind for AssocItemKind {
|
|||
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||
visitor.visit_qself(qself);
|
||||
visitor.visit_path(prefix);
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(rename);
|
||||
if let Some(suffixes) = suffixes {
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(rename);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(body) = body {
|
||||
|
|
@ -1289,7 +1310,12 @@ pub fn noop_flat_map_item<K: NoopVisitItemKind>(
|
|||
impl NoopVisitItemKind for ForeignItemKind {
|
||||
fn noop_visit(&mut self, visitor: &mut impl MutVisitor) {
|
||||
match self {
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem {
|
||||
ty,
|
||||
mutability: _,
|
||||
expr,
|
||||
safety: _,
|
||||
}) => {
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(expr, |expr| visitor.visit_expr(expr));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ impl<'a, T> IntoIterator for &'a P<[T]> {
|
|||
type Item = &'a T;
|
||||
type IntoIter = slice::Iter<'a, T>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.ptr.into_iter()
|
||||
self.ptr.iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> boo
|
|||
kw::Unsafe,
|
||||
kw::While,
|
||||
kw::Yield,
|
||||
kw::Safe,
|
||||
kw::Static,
|
||||
]
|
||||
.contains(&name)
|
||||
|
|
@ -577,6 +578,7 @@ impl Token {
|
|||
kw::Impl,
|
||||
kw::Unsafe,
|
||||
kw::Const,
|
||||
kw::Safe,
|
||||
kw::Static,
|
||||
kw::Union,
|
||||
kw::Macro,
|
||||
|
|
|
|||
|
|
@ -661,11 +661,11 @@ impl TokenStream {
|
|||
if attr_style == AttrStyle::Inner {
|
||||
vec![
|
||||
TokenTree::token_joint(token::Pound, span),
|
||||
TokenTree::token_alone(token::Not, span),
|
||||
TokenTree::token_joint_hidden(token::Not, span),
|
||||
body,
|
||||
]
|
||||
} else {
|
||||
vec![TokenTree::token_alone(token::Pound, span), body]
|
||||
vec![TokenTree::token_joint_hidden(token::Pound, span), body]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,8 +81,17 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum TrailingBrace<'a> {
|
||||
/// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
|
||||
/// We will suggest changing the macro call to a different delimiter.
|
||||
MacCall(&'a ast::MacCall),
|
||||
/// Trailing brace in any other expression, such as `a + B {}`. We will
|
||||
/// suggest wrapping the innermost expression in parentheses: `a + (B {})`.
|
||||
Expr(&'a ast::Expr),
|
||||
}
|
||||
|
||||
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
|
||||
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
||||
loop {
|
||||
match &expr.kind {
|
||||
AddrOf(_, _, e)
|
||||
|
|
@ -111,10 +120,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
| Struct(..)
|
||||
| TryBlock(..)
|
||||
| While(..)
|
||||
| ConstBlock(_) => break Some(expr),
|
||||
| ConstBlock(_) => break Some(TrailingBrace::Expr(expr)),
|
||||
|
||||
Cast(_, ty) => {
|
||||
break type_trailing_braced_mac_call(ty).map(TrailingBrace::MacCall);
|
||||
}
|
||||
|
||||
MacCall(mac) => {
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(expr);
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(TrailingBrace::MacCall(mac));
|
||||
}
|
||||
|
||||
InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
|
||||
|
|
@ -131,7 +144,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
| MethodCall(_)
|
||||
| Tup(_)
|
||||
| Lit(_)
|
||||
| Cast(_, _)
|
||||
| Type(_, _)
|
||||
| Await(_, _)
|
||||
| Field(_, _)
|
||||
|
|
@ -148,3 +160,80 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If the type's last token is `}`, it must be due to a braced macro call, such
|
||||
/// as in `*const brace! { ... }`. Returns that trailing macro call.
|
||||
fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
||||
loop {
|
||||
match &ty.kind {
|
||||
ast::TyKind::MacCall(mac) => {
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(mac);
|
||||
}
|
||||
|
||||
ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => {
|
||||
ty = &mut_ty.ty;
|
||||
}
|
||||
|
||||
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
|
||||
ast::FnRetTy::Default(_) => break None,
|
||||
ast::FnRetTy::Ty(ret) => ty = ret,
|
||||
},
|
||||
|
||||
ast::TyKind::Path(_, path) => match path_return_type(path) {
|
||||
Some(trailing_ty) => ty = trailing_ty,
|
||||
None => break None,
|
||||
},
|
||||
|
||||
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
|
||||
match bounds.last() {
|
||||
Some(ast::GenericBound::Trait(bound, _)) => {
|
||||
match path_return_type(&bound.trait_ref.path) {
|
||||
Some(trailing_ty) => ty = trailing_ty,
|
||||
None => break None,
|
||||
}
|
||||
}
|
||||
Some(ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..)) | None => {
|
||||
break None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast::TyKind::Slice(..)
|
||||
| ast::TyKind::Array(..)
|
||||
| ast::TyKind::Never
|
||||
| ast::TyKind::Tup(..)
|
||||
| ast::TyKind::Paren(..)
|
||||
| ast::TyKind::Typeof(..)
|
||||
| ast::TyKind::Infer
|
||||
| ast::TyKind::ImplicitSelf
|
||||
| ast::TyKind::CVarArgs
|
||||
| ast::TyKind::Pat(..)
|
||||
| ast::TyKind::Dummy
|
||||
| ast::TyKind::Err(..) => break None,
|
||||
|
||||
// These end in brace, but cannot occur in a let-else statement.
|
||||
// They are only parsed as fields of a data structure. For the
|
||||
// purpose of denying trailing braces in the expression of a
|
||||
// let-else, we can disregard these.
|
||||
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the trailing return type in the given path, if it has one.
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// ::std::ops::FnOnce(&str) -> fn() -> *const c_void
|
||||
/// ^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> {
|
||||
let last_segment = path.segments.last()?;
|
||||
let args = last_segment.args.as_ref()?;
|
||||
match &**args {
|
||||
ast::GenericArgs::Parenthesized(args) => match &args.output {
|
||||
ast::FnRetTy::Default(_) => None,
|
||||
ast::FnRetTy::Ty(ret) => Some(ret),
|
||||
},
|
||||
ast::GenericArgs::AngleBracketed(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,16 @@ pub enum BoundKind {
|
|||
/// E.g., `trait A: B`
|
||||
SuperTraits,
|
||||
}
|
||||
impl BoundKind {
|
||||
pub fn descr(self) -> &'static str {
|
||||
match self {
|
||||
BoundKind::Bound => "bounds",
|
||||
BoundKind::Impl => "`impl Trait`",
|
||||
BoundKind::TraitObject => "`dyn` trait object bounds",
|
||||
BoundKind::SuperTraits => "supertrait bounds",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum FnKind<'a> {
|
||||
|
|
@ -246,8 +256,11 @@ pub trait Visitor<'ast>: Sized {
|
|||
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) -> Self::Result {
|
||||
walk_generic_arg(self, generic_arg)
|
||||
}
|
||||
fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) -> Self::Result {
|
||||
walk_assoc_constraint(self, constraint)
|
||||
fn visit_assoc_item_constraint(
|
||||
&mut self,
|
||||
constraint: &'ast AssocItemConstraint,
|
||||
) -> Self::Result {
|
||||
walk_assoc_item_constraint(self, constraint)
|
||||
}
|
||||
fn visit_attribute(&mut self, attr: &'ast Attribute) -> Self::Result {
|
||||
walk_attribute(self, attr)
|
||||
|
|
@ -331,7 +344,7 @@ impl WalkItemKind for ItemKind {
|
|||
match self {
|
||||
ItemKind::ExternCrate(_) => {}
|
||||
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)),
|
||||
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
|
||||
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
|
|
@ -395,7 +408,14 @@ impl WalkItemKind for ItemKind {
|
|||
}
|
||||
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
||||
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
|
||||
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
|
||||
ItemKind::Delegation(box Delegation {
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
rename,
|
||||
body,
|
||||
from_glob: _,
|
||||
}) => {
|
||||
if let Some(qself) = qself {
|
||||
try_visit!(visitor.visit_ty(&qself.ty));
|
||||
}
|
||||
|
|
@ -408,10 +428,12 @@ impl WalkItemKind for ItemKind {
|
|||
try_visit!(visitor.visit_ty(&qself.ty));
|
||||
}
|
||||
try_visit!(visitor.visit_path(prefix, item.id));
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(*ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(*rename);
|
||||
if let Some(suffixes) = suffixes {
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(*ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(*rename);
|
||||
}
|
||||
}
|
||||
}
|
||||
visit_opt!(visitor, visit_block, body);
|
||||
|
|
@ -494,13 +516,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
|||
TyKind::TraitObject(bounds, ..) => {
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
|
||||
}
|
||||
TyKind::ImplTrait(_, bounds, precise_capturing) => {
|
||||
TyKind::ImplTrait(_, bounds) => {
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
|
||||
if let Some((precise_capturing, _span)) = precise_capturing.as_deref() {
|
||||
for arg in precise_capturing {
|
||||
try_visit!(visitor.visit_precise_capturing_arg(arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)),
|
||||
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}
|
||||
|
|
@ -558,7 +575,7 @@ where
|
|||
match arg {
|
||||
AngleBracketedArg::Arg(a) => try_visit!(visitor.visit_generic_arg(a)),
|
||||
AngleBracketedArg::Constraint(c) => {
|
||||
try_visit!(visitor.visit_assoc_constraint(c))
|
||||
try_visit!(visitor.visit_assoc_item_constraint(c))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -582,18 +599,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(
|
||||
pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
constraint: &'a AssocConstraint,
|
||||
constraint: &'a AssocItemConstraint,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_ident(constraint.ident));
|
||||
visit_opt!(visitor, visit_generic_args, &constraint.gen_args);
|
||||
match &constraint.kind {
|
||||
AssocConstraintKind::Equality { term } => match term {
|
||||
AssocItemConstraintKind::Equality { term } => match term {
|
||||
Term::Ty(ty) => try_visit!(visitor.visit_ty(ty)),
|
||||
Term::Const(c) => try_visit!(visitor.visit_anon_const(c)),
|
||||
},
|
||||
AssocConstraintKind::Bound { bounds } => {
|
||||
AssocItemConstraintKind::Bound { bounds } => {
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||
}
|
||||
}
|
||||
|
|
@ -655,7 +672,12 @@ impl WalkItemKind for ForeignItemKind {
|
|||
) -> V::Result {
|
||||
let &Item { id, span, ident, ref vis, .. } = item;
|
||||
match self {
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem {
|
||||
ty,
|
||||
mutability: _,
|
||||
expr,
|
||||
safety: _,
|
||||
}) => {
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
|
|
@ -680,6 +702,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
|
|||
match bound {
|
||||
GenericBound::Trait(typ, _modifier) => visitor.visit_poly_trait_ref(typ),
|
||||
GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound),
|
||||
GenericBound::Use(args, _) => {
|
||||
walk_list!(visitor, visit_precise_capturing_arg, args);
|
||||
V::Result::output()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -820,7 +846,14 @@ impl WalkItemKind for AssocItemKind {
|
|||
AssocItemKind::MacCall(mac) => {
|
||||
try_visit!(visitor.visit_mac_call(mac));
|
||||
}
|
||||
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
|
||||
AssocItemKind::Delegation(box Delegation {
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
rename,
|
||||
body,
|
||||
from_glob: _,
|
||||
}) => {
|
||||
if let Some(qself) = qself {
|
||||
try_visit!(visitor.visit_ty(&qself.ty));
|
||||
}
|
||||
|
|
@ -833,10 +866,12 @@ impl WalkItemKind for AssocItemKind {
|
|||
try_visit!(visitor.visit_ty(&qself.ty));
|
||||
}
|
||||
try_visit!(visitor.visit_path(prefix, item.id));
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(*ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(*rename);
|
||||
if let Some(suffixes) = suffixes {
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(*ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(*rename);
|
||||
}
|
||||
}
|
||||
}
|
||||
visit_opt!(visitor, visit_block, body);
|
||||
|
|
@ -852,10 +887,10 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(
|
|||
ctxt: AssocCtxt,
|
||||
) -> V::Result {
|
||||
let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(kind.walk(item, ctxt, visitor));
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
|||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
rustc_span = { path = "../rustc_span", optional = true }
|
||||
smallvec = { version = "1.8.1" }
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// tidy-alphabetical-start
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
#![cfg_attr(feature = "nightly", feature(never_type))]
|
||||
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ ast_lowering_never_pattern_with_guard =
|
|||
a guard on a never pattern will never be run
|
||||
.suggestion = remove this guard
|
||||
|
||||
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
|
||||
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
|
||||
|
||||
ast_lowering_previously_used_here = previously used here
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
StmtKind::Empty => {}
|
||||
StmtKind::MacCall(..) => panic!("shouldn't exist here"),
|
||||
}
|
||||
ast_stmts = &ast_stmts[1..];
|
||||
ast_stmts = tail;
|
||||
}
|
||||
(self.arena.alloc_from_iter(stmts), expr)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
return false;
|
||||
};
|
||||
if let Some(local_sig_id) = sig_id.as_local() {
|
||||
self.resolver.delegation_fn_sigs[&local_sig_id].has_self
|
||||
// The value may be missing due to recursive delegation.
|
||||
// Error will be emmited later during HIR ty lowering.
|
||||
self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self)
|
||||
} else {
|
||||
match self.tcx.def_kind(sig_id) {
|
||||
DefKind::Fn => false,
|
||||
|
|
|
|||
|
|
@ -1716,24 +1716,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// `mut iter => { ... }`
|
||||
let iter_arm = self.arm(iter_pat, loop_expr);
|
||||
|
||||
let into_iter_expr = match loop_kind {
|
||||
let match_expr = match loop_kind {
|
||||
ForLoopKind::For => {
|
||||
// `::std::iter::IntoIterator::into_iter(<head>)`
|
||||
self.expr_call_lang_item_fn(
|
||||
let into_iter_expr = self.expr_call_lang_item_fn(
|
||||
head_span,
|
||||
hir::LangItem::IntoIterIntoIter,
|
||||
arena_vec![self; head],
|
||||
)
|
||||
}
|
||||
// ` unsafe { Pin::new_unchecked(&mut into_async_iter(<head>)) }`
|
||||
ForLoopKind::ForAwait => {
|
||||
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
|
||||
let iter = self.expr_call_lang_item_fn(
|
||||
head_span,
|
||||
hir::LangItem::IntoAsyncIterIntoIter,
|
||||
arena_vec![self; head],
|
||||
);
|
||||
let iter = self.expr_mut_addr_of(head_span, iter);
|
||||
|
||||
self.arena.alloc(self.expr_match(
|
||||
for_span,
|
||||
into_iter_expr,
|
||||
arena_vec![self; iter_arm],
|
||||
hir::MatchSource::ForLoopDesugar,
|
||||
))
|
||||
}
|
||||
// `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }`
|
||||
ForLoopKind::ForAwait => {
|
||||
let iter_ident = iter;
|
||||
let (async_iter_pat, async_iter_pat_id) =
|
||||
self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT);
|
||||
let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id);
|
||||
// `Pin::new_unchecked(...)`
|
||||
let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
|
||||
head_span,
|
||||
|
|
@ -1742,17 +1746,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
));
|
||||
// `unsafe { ... }`
|
||||
let iter = self.arena.alloc(self.expr_unsafe(iter));
|
||||
iter
|
||||
let inner_match_expr = self.arena.alloc(self.expr_match(
|
||||
for_span,
|
||||
iter,
|
||||
arena_vec![self; iter_arm],
|
||||
hir::MatchSource::ForLoopDesugar,
|
||||
));
|
||||
|
||||
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
|
||||
let iter = self.expr_call_lang_item_fn(
|
||||
head_span,
|
||||
hir::LangItem::IntoAsyncIterIntoIter,
|
||||
arena_vec![self; head],
|
||||
);
|
||||
let iter_arm = self.arm(async_iter_pat, inner_match_expr);
|
||||
self.arena.alloc(self.expr_match(
|
||||
for_span,
|
||||
iter,
|
||||
arena_vec![self; iter_arm],
|
||||
hir::MatchSource::ForLoopDesugar,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let match_expr = self.arena.alloc(self.expr_match(
|
||||
for_span,
|
||||
into_iter_expr,
|
||||
arena_vec![self; iter_arm],
|
||||
hir::MatchSource::ForLoopDesugar,
|
||||
));
|
||||
|
||||
// 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
|
||||
|
|
@ -1805,6 +1821,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let attr = attr::mk_attr_nested_word(
|
||||
&self.tcx.sess.psess.attr_id_generator,
|
||||
AttrStyle::Outer,
|
||||
Safety::Default,
|
||||
sym::allow,
|
||||
sym::unreachable_code,
|
||||
self.lower_span(span),
|
||||
|
|
|
|||
|
|
@ -333,10 +333,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) {
|
||||
self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding));
|
||||
self.with_parent(type_binding.hir_id, |this| {
|
||||
intravisit::walk_assoc_type_binding(this, type_binding)
|
||||
fn visit_assoc_item_constraint(&mut self, constraint: &'hir AssocItemConstraint<'hir>) {
|
||||
self.insert(constraint.span, constraint.hir_id, Node::AssocItemConstraint(constraint));
|
||||
self.with_parent(constraint.hir_id, |this| {
|
||||
intravisit::walk_assoc_item_constraint(this, constraint)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
|
||||
}
|
||||
ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => {
|
||||
ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => {
|
||||
let (ty, body_id) =
|
||||
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
|
||||
hir::ItemKind::Static(ty, *m, body_id)
|
||||
|
|
@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
|
||||
};
|
||||
hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
|
||||
safety: self.lower_safety(*safety),
|
||||
safety: self.lower_safety(*safety, hir::Safety::Safe),
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span,
|
||||
|
|
@ -418,7 +418,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let items = this.arena.alloc_from_iter(
|
||||
items.iter().map(|item| this.lower_trait_item_ref(item)),
|
||||
);
|
||||
let safety = this.lower_safety(*safety);
|
||||
let safety = this.lower_safety(*safety, hir::Safety::Safe);
|
||||
(safety, items, bounds)
|
||||
},
|
||||
);
|
||||
|
|
@ -660,13 +660,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
this.lower_fn_params_to_names(fdec),
|
||||
)
|
||||
});
|
||||
let safety = self.lower_safety(sig.header.safety, hir::Safety::Unsafe);
|
||||
|
||||
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
|
||||
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics, safety)
|
||||
}
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty, mutability, expr: _ }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem {
|
||||
ty,
|
||||
mutability,
|
||||
expr: _,
|
||||
safety,
|
||||
}) => {
|
||||
let ty = self
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
hir::ForeignItemKind::Static(ty, *mutability)
|
||||
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
|
||||
|
||||
hir::ForeignItemKind::Static(ty, *mutability, safety)
|
||||
}
|
||||
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
|
||||
ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
|
||||
|
|
@ -1311,6 +1319,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
|
||||
};
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
|
||||
let span = if let FnRetTy::Default(span) = decl.output
|
||||
&& matches!(coroutine_source, rustc_hir::CoroutineSource::Closure)
|
||||
{
|
||||
body_span.with_lo(span.lo())
|
||||
} else {
|
||||
body_span
|
||||
};
|
||||
let coroutine_expr = self.make_desugared_coroutine_expr(
|
||||
// The default capture mode here is by-ref. Later on during upvar analysis,
|
||||
// we will force the captured arguments to by-move, but for async closures,
|
||||
|
|
@ -1319,7 +1335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
CaptureBy::Ref,
|
||||
closure_id,
|
||||
None,
|
||||
body_span,
|
||||
span,
|
||||
desugaring_kind,
|
||||
coroutine_source,
|
||||
mkbody,
|
||||
|
|
@ -1360,7 +1376,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::IsAsync::NotAsync
|
||||
};
|
||||
hir::FnHeader {
|
||||
safety: self.lower_safety(h.safety),
|
||||
safety: self.lower_safety(h.safety, hir::Safety::Safe),
|
||||
asyncness: asyncness,
|
||||
constness: self.lower_constness(h.constness),
|
||||
abi: self.lower_extern(h.ext),
|
||||
|
|
@ -1410,10 +1426,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_safety(&mut self, s: Safety) -> hir::Safety {
|
||||
pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety {
|
||||
match s {
|
||||
Safety::Unsafe(_) => hir::Safety::Unsafe,
|
||||
Safety::Default => hir::Safety::Safe,
|
||||
Safety::Default => default,
|
||||
Safety::Safe(_) => hir::Safety::Safe,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@
|
|||
//! get confused if the spans from leaf AST nodes occur in multiple places
|
||||
//! in the HIR, especially for multiple identifiers.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
|
|
@ -48,10 +50,10 @@ use rustc_data_structures::fx::FxIndexSet;
|
|||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::{self as hir};
|
||||
use rustc_hir::{
|
||||
ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
|
||||
};
|
||||
|
|
@ -186,7 +188,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dcx(&self) -> &'hir DiagCtxt {
|
||||
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'hir> {
|
||||
self.tcx.dcx()
|
||||
}
|
||||
}
|
||||
|
|
@ -905,6 +907,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let kind = match attr.kind {
|
||||
AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr {
|
||||
item: AttrItem {
|
||||
unsafety: normal.item.unsafety,
|
||||
path: normal.item.path.clone(),
|
||||
args: self.lower_attr_args(&normal.item.args),
|
||||
tokens: None,
|
||||
|
|
@ -961,24 +964,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() }
|
||||
}
|
||||
|
||||
/// Given an associated type constraint like one of these:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// T: Iterator<Item: Debug>
|
||||
/// ^^^^^^^^^^^
|
||||
/// T: Iterator<Item = Debug>
|
||||
/// ^^^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// returns a `hir::TypeBinding` representing `Item`.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_assoc_ty_constraint(
|
||||
/// Lower an associated item constraint.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn lower_assoc_item_constraint(
|
||||
&mut self,
|
||||
constraint: &AssocConstraint,
|
||||
constraint: &AssocItemConstraint,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::TypeBinding<'hir> {
|
||||
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
|
||||
// lower generic arguments of identifier in constraint
|
||||
) -> hir::AssocItemConstraint<'hir> {
|
||||
debug!(?constraint, ?itctx);
|
||||
// Lower the generic arguments for the associated item.
|
||||
let gen_args = if let Some(gen_args) = &constraint.gen_args {
|
||||
let gen_args_ctor = match gen_args {
|
||||
GenericArgs::AngleBracketed(data) => {
|
||||
|
|
@ -994,7 +988,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
};
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
constraints: &[],
|
||||
parenthesized,
|
||||
span: data.inputs_span,
|
||||
}
|
||||
|
|
@ -1024,7 +1018,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
err.emit();
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
constraints: &[],
|
||||
parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
|
||||
span: data.span,
|
||||
}
|
||||
|
|
@ -1046,14 +1040,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.arena.alloc(hir::GenericArgs::none())
|
||||
};
|
||||
let kind = match &constraint.kind {
|
||||
AssocConstraintKind::Equality { term } => {
|
||||
AssocItemConstraintKind::Equality { term } => {
|
||||
let term = match term {
|
||||
Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
|
||||
Term::Const(c) => self.lower_anon_const(c).into(),
|
||||
};
|
||||
hir::TypeBindingKind::Equality { term }
|
||||
hir::AssocItemConstraintKind::Equality { term }
|
||||
}
|
||||
AssocConstraintKind::Bound { bounds } => {
|
||||
AssocItemConstraintKind::Bound { bounds } => {
|
||||
// Disallow ATB in dyn types
|
||||
if self.is_in_dyn_type {
|
||||
let suggestion = match itctx {
|
||||
|
|
@ -1077,18 +1071,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
});
|
||||
let err_ty =
|
||||
&*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
|
||||
hir::TypeBindingKind::Equality { term: err_ty.into() }
|
||||
hir::AssocItemConstraintKind::Equality { term: err_ty.into() }
|
||||
} else {
|
||||
// Desugar `AssocTy: Bounds` into a type binding where the
|
||||
// Desugar `AssocTy: Bounds` into an assoc type binding where the
|
||||
// later desugars into a trait predicate.
|
||||
let bounds = self.lower_param_bounds(bounds, itctx);
|
||||
|
||||
hir::TypeBindingKind::Constraint { bounds }
|
||||
hir::AssocItemConstraintKind::Bound { bounds }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
hir::TypeBinding {
|
||||
hir::AssocItemConstraint {
|
||||
hir_id: self.lower_node_id(constraint.id),
|
||||
ident: self.lower_ident(constraint.ident),
|
||||
gen_args,
|
||||
|
|
@ -1324,7 +1318,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||
hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
|
||||
generic_params,
|
||||
safety: self.lower_safety(f.safety),
|
||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||
abi: self.lower_extern(f.ext),
|
||||
decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
|
||||
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||
|
|
@ -1390,6 +1384,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
None
|
||||
}
|
||||
// Ignore `use` syntax since that is not valid in objects.
|
||||
GenericBound::Use(_, span) => {
|
||||
this.dcx()
|
||||
.span_delayed_bug(*span, "use<> not allowed in dyn types");
|
||||
None
|
||||
}
|
||||
}));
|
||||
let lifetime_bound =
|
||||
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
|
||||
|
|
@ -1397,7 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
});
|
||||
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
|
||||
}
|
||||
TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
|
||||
TyKind::ImplTrait(def_node_id, bounds) => {
|
||||
let span = t.span;
|
||||
match itctx {
|
||||
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
|
||||
|
|
@ -1407,12 +1407,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
bounds,
|
||||
fn_kind,
|
||||
itctx,
|
||||
precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)),
|
||||
),
|
||||
ImplTraitContext::Universal => {
|
||||
if let Some(&(_, span)) = precise_capturing.as_deref() {
|
||||
if let Some(span) = bounds.iter().find_map(|bound| match *bound {
|
||||
ast::GenericBound::Use(_, span) => Some(span),
|
||||
_ => None,
|
||||
}) {
|
||||
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
|
||||
};
|
||||
}
|
||||
|
||||
let span = t.span;
|
||||
|
||||
// HACK: pprust breaks strings with newlines when the type
|
||||
|
|
@ -1523,7 +1526,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
bounds: &GenericBounds,
|
||||
fn_kind: Option<FnDeclKind>,
|
||||
itctx: ImplTraitContext,
|
||||
precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
|
||||
) -> hir::TyKind<'hir> {
|
||||
// Make sure we know that some funky desugaring has been going on here.
|
||||
// This is a first: there is code in other places like for loop
|
||||
|
|
@ -1532,59 +1534,64 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// frequently opened issues show.
|
||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
||||
|
||||
let captured_lifetimes_to_duplicate =
|
||||
if let Some((precise_capturing, _)) = precise_capturing_args {
|
||||
// We'll actually validate these later on; all we need is the list of
|
||||
// lifetimes to duplicate during this portion of lowering.
|
||||
precise_capturing
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => Some(*lt),
|
||||
PreciseCapturingArg::Arg(..) => None,
|
||||
})
|
||||
// Add in all the lifetimes mentioned in the bounds. We will error
|
||||
// them out later, but capturing them here is important to make sure
|
||||
// they actually get resolved in resolve_bound_vars.
|
||||
.chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
|
||||
.collect()
|
||||
} else {
|
||||
match origin {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
// type alias impl trait and associated type position impl trait were
|
||||
// decided to capture all in-scope lifetimes, which we collect for
|
||||
// all opaques during resolution.
|
||||
let captured_lifetimes_to_duplicate = if let Some(args) =
|
||||
// We only look for one `use<...>` syntax since we syntactially reject more than one.
|
||||
bounds.iter().find_map(
|
||||
|bound| match bound {
|
||||
ast::GenericBound::Use(a, _) => Some(a),
|
||||
_ => None,
|
||||
},
|
||||
) {
|
||||
// We'll actually validate these later on; all we need is the list of
|
||||
// lifetimes to duplicate during this portion of lowering.
|
||||
args.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => Some(*lt),
|
||||
PreciseCapturingArg::Arg(..) => None,
|
||||
})
|
||||
// Add in all the lifetimes mentioned in the bounds. We will error
|
||||
// them out later, but capturing them here is important to make sure
|
||||
// they actually get resolved in resolve_bound_vars.
|
||||
.chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
|
||||
.collect()
|
||||
} else {
|
||||
match origin {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
// type alias impl trait and associated type position impl trait were
|
||||
// decided to capture all in-scope lifetimes, which we collect for
|
||||
// all opaques during resolution.
|
||||
self.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect()
|
||||
}
|
||||
hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||
if matches!(
|
||||
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
|
||||
FnDeclKind::Impl | FnDeclKind::Trait
|
||||
) || self.tcx.features().lifetime_capture_rules_2024
|
||||
|| span.at_least_rust_2024()
|
||||
{
|
||||
// return-position impl trait in trait was decided to capture all
|
||||
// in-scope lifetimes, which we collect for all opaques during resolution.
|
||||
self.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect()
|
||||
}
|
||||
hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||
if matches!(
|
||||
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
|
||||
FnDeclKind::Impl | FnDeclKind::Trait
|
||||
) || self.tcx.features().lifetime_capture_rules_2024
|
||||
|| span.at_least_rust_2024()
|
||||
{
|
||||
// return-position impl trait in trait was decided to capture all
|
||||
// in-scope lifetimes, which we collect for all opaques during resolution.
|
||||
self.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect()
|
||||
} else {
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
|
||||
// example, we only need to duplicate lifetimes that appear in the
|
||||
// bounds, since those are the only ones that are captured by the opaque.
|
||||
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
|
||||
}
|
||||
}
|
||||
hir::OpaqueTyOrigin::AsyncFn(..) => {
|
||||
unreachable!("should be using `lower_async_fn_ret_ty`")
|
||||
} else {
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
|
||||
// example, we only need to duplicate lifetimes that appear in the
|
||||
// bounds, since those are the only ones that are captured by the opaque.
|
||||
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
|
||||
}
|
||||
}
|
||||
};
|
||||
hir::OpaqueTyOrigin::AsyncFn(..) => {
|
||||
unreachable!("should be using `lower_async_fn_ret_ty`")
|
||||
}
|
||||
}
|
||||
};
|
||||
debug!(?captured_lifetimes_to_duplicate);
|
||||
|
||||
self.lower_opaque_inner(
|
||||
|
|
@ -1594,7 +1601,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
captured_lifetimes_to_duplicate,
|
||||
span,
|
||||
opaque_ty_span,
|
||||
precise_capturing_args,
|
||||
|this| this.lower_param_bounds(bounds, itctx),
|
||||
)
|
||||
}
|
||||
|
|
@ -1607,7 +1613,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
|
||||
span: Span,
|
||||
opaque_ty_span: Span,
|
||||
precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
|
||||
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
|
||||
) -> hir::TyKind<'hir> {
|
||||
let opaque_ty_def_id = self.create_def(
|
||||
|
|
@ -1694,18 +1699,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Install the remapping from old to new (if any). This makes sure that
|
||||
// any lifetimes that would have resolved to the def-id of captured
|
||||
// lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
|
||||
let (bounds, precise_capturing_args) =
|
||||
this.with_remapping(captured_to_synthesized_mapping, |this| {
|
||||
(
|
||||
lower_item_bounds(this),
|
||||
precise_capturing_args.map(|(precise_capturing, span)| {
|
||||
(
|
||||
this.lower_precise_capturing_args(precise_capturing),
|
||||
this.lower_span(span),
|
||||
)
|
||||
}),
|
||||
)
|
||||
});
|
||||
let bounds = this
|
||||
.with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
|
||||
|
||||
let generic_params =
|
||||
this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
|
||||
|
|
@ -1750,7 +1745,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
origin,
|
||||
lifetime_mapping,
|
||||
in_trait,
|
||||
precise_capturing_args,
|
||||
};
|
||||
|
||||
// Generate an `type Foo = impl Trait;` declaration.
|
||||
|
|
@ -1961,7 +1955,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
captured_lifetimes,
|
||||
span,
|
||||
opaque_ty_span,
|
||||
None,
|
||||
|this| {
|
||||
let bound = this.lower_coroutine_fn_output_type_to_bound(
|
||||
output,
|
||||
|
|
@ -2008,7 +2001,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
let bound_args = self.arena.alloc(hir::GenericArgs {
|
||||
args: &[],
|
||||
bindings: arena_vec![self; self.assoc_ty_binding(assoc_ty_name, opaque_ty_span, output_ty)],
|
||||
constraints: arena_vec![self; self.assoc_ty_binding(assoc_ty_name, opaque_ty_span, output_ty)],
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span_ext: DUMMY_SP,
|
||||
});
|
||||
|
|
@ -2044,6 +2037,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
GenericBound::Outlives(lifetime) => {
|
||||
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
|
||||
}
|
||||
GenericBound::Use(args, span) => hir::GenericBound::Use(
|
||||
self.lower_precise_capturing_args(args),
|
||||
self.lower_span(*span),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2581,10 +2578,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper struct for delayed construction of GenericArgs.
|
||||
/// Helper struct for the delayed construction of [`hir::GenericArgs`].
|
||||
struct GenericArgsCtor<'hir> {
|
||||
args: SmallVec<[hir::GenericArg<'hir>; 4]>,
|
||||
bindings: &'hir [hir::TypeBinding<'hir>],
|
||||
constraints: &'hir [hir::AssocItemConstraint<'hir>],
|
||||
parenthesized: hir::GenericArgsParentheses,
|
||||
span: Span,
|
||||
}
|
||||
|
|
@ -2664,14 +2661,14 @@ impl<'hir> GenericArgsCtor<'hir> {
|
|||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.args.is_empty()
|
||||
&& self.bindings.is_empty()
|
||||
&& self.constraints.is_empty()
|
||||
&& self.parenthesized == hir::GenericArgsParentheses::No
|
||||
}
|
||||
|
||||
fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
|
||||
let ga = hir::GenericArgs {
|
||||
args: this.arena.alloc_from_iter(self.args),
|
||||
bindings: self.bindings,
|
||||
constraints: self.constraints,
|
||||
parenthesized: self.parenthesized,
|
||||
span_ext: this.lower_span(self.span),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
(
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
constraints: &[],
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span: path_span.shrink_to_hi(),
|
||||
},
|
||||
|
|
@ -390,13 +390,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
AngleBracketedArg::Constraint(_) => None,
|
||||
})
|
||||
.collect();
|
||||
let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
|
||||
AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
|
||||
AngleBracketedArg::Arg(_) => None,
|
||||
}));
|
||||
let constraints =
|
||||
self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
|
||||
AngleBracketedArg::Constraint(c) => {
|
||||
Some(self.lower_assoc_item_constraint(c, itctx))
|
||||
}
|
||||
AngleBracketedArg::Arg(_) => None,
|
||||
}));
|
||||
let ctor = GenericArgsCtor {
|
||||
args,
|
||||
bindings,
|
||||
constraints,
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span: data.span,
|
||||
};
|
||||
|
|
@ -454,12 +457,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
Some(bound_modifier_allowed_features),
|
||||
);
|
||||
}
|
||||
let binding = self.assoc_ty_binding(sym::Output, output_span, output_ty);
|
||||
let constraint = self.assoc_ty_binding(sym::Output, output_span, output_ty);
|
||||
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args,
|
||||
bindings: arena_vec![self; binding],
|
||||
constraints: arena_vec![self; constraint],
|
||||
parenthesized: hir::GenericArgsParentheses::ParenSugar,
|
||||
span: data.inputs_span,
|
||||
},
|
||||
|
|
@ -467,24 +470,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
)
|
||||
}
|
||||
|
||||
/// An associated type binding `$assoc_ty_name = $ty`.
|
||||
/// An associated type binding (i.e., associated type equality constraint).
|
||||
pub(crate) fn assoc_ty_binding(
|
||||
&mut self,
|
||||
assoc_ty_name: rustc_span::Symbol,
|
||||
span: Span,
|
||||
ty: &'hir hir::Ty<'hir>,
|
||||
) -> hir::TypeBinding<'hir> {
|
||||
) -> hir::AssocItemConstraint<'hir> {
|
||||
let ident = Ident::with_dummy_span(assoc_ty_name);
|
||||
let kind = hir::TypeBindingKind::Equality { term: ty.into() };
|
||||
let kind = hir::AssocItemConstraintKind::Equality { term: ty.into() };
|
||||
let args = arena_vec![self;];
|
||||
let bindings = arena_vec![self;];
|
||||
let constraints = arena_vec![self;];
|
||||
let gen_args = self.arena.alloc(hir::GenericArgs {
|
||||
args,
|
||||
bindings,
|
||||
constraints,
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span_ext: DUMMY_SP,
|
||||
});
|
||||
hir::TypeBinding {
|
||||
hir::AssocItemConstraint {
|
||||
hir_id: self.next_id(),
|
||||
gen_args,
|
||||
span: self.lower_span(span),
|
||||
|
|
|
|||
|
|
@ -55,9 +55,6 @@ ast_passes_const_without_body =
|
|||
ast_passes_constraint_on_negative_bound =
|
||||
associated type constraints not allowed on negative bounds
|
||||
|
||||
ast_passes_deprecated_where_clause_location =
|
||||
where clause not allowed here
|
||||
|
||||
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
|
||||
.label = not supported
|
||||
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
|
||||
|
|
@ -70,6 +67,9 @@ ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have quali
|
|||
.label = in this `extern` block
|
||||
.suggestion = remove this qualifier
|
||||
|
||||
ast_passes_extern_invalid_safety = items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
.suggestion = add unsafe to this `extern` block
|
||||
|
||||
ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
|
||||
.label = in this `extern` block
|
||||
.note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
|
||||
|
|
@ -80,8 +80,6 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de
|
|||
.suggestion = remove the {$remove_descr}
|
||||
.label = `extern` block begins here
|
||||
|
||||
ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
|
||||
|
||||
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
|
||||
.suggestion = remove the attribute
|
||||
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
|
||||
|
|
@ -97,9 +95,6 @@ ast_passes_fn_body_extern = incorrect function inside `extern` block
|
|||
ast_passes_fn_param_c_var_args_not_last =
|
||||
`...` must be the last argument of a C-variadic function
|
||||
|
||||
ast_passes_fn_param_c_var_args_only =
|
||||
C-variadic function must be declared with at least one named argument
|
||||
|
||||
ast_passes_fn_param_doc_comment =
|
||||
documentation comments cannot be applied to function parameters
|
||||
.label = doc comments are not allowed here
|
||||
|
|
@ -182,6 +177,8 @@ ast_passes_match_arm_with_no_body =
|
|||
`match` arm with no body
|
||||
.suggestion = add a body after the pattern
|
||||
|
||||
ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe
|
||||
|
||||
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
|
||||
.help = consider using the `#[path]` attribute to specify filesystem path
|
||||
|
||||
|
|
@ -218,6 +215,11 @@ ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer t
|
|||
ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
|
||||
.label = pattern not allowed in foreign function
|
||||
|
||||
ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax
|
||||
.label = second `use<...>` here
|
||||
|
||||
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
|
||||
|
||||
ast_passes_show_span = {$msg}
|
||||
|
||||
ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@ use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}
|
|||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
};
|
||||
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
|
||||
use rustc_session::Session;
|
||||
|
|
@ -27,7 +29,6 @@ use std::ops::{Deref, DerefMut};
|
|||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::errors;
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
|
||||
enum SelfSemantic {
|
||||
|
|
@ -87,6 +88,9 @@ struct AstValidator<'a> {
|
|||
/// or `Foo::Bar<impl Trait>`
|
||||
is_impl_trait_banned: bool,
|
||||
|
||||
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
||||
extern_mod_safety: Option<Safety>,
|
||||
|
||||
lint_buffer: &'a mut LintBuffer,
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +121,12 @@ impl<'a> AstValidator<'a> {
|
|||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
f(self);
|
||||
self.extern_mod_safety = old;
|
||||
}
|
||||
|
||||
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.is_impl_trait_banned, true);
|
||||
f(self);
|
||||
|
|
@ -184,8 +194,24 @@ impl<'a> AstValidator<'a> {
|
|||
// Mirrors `visit::walk_ty`, but tracks relevant state.
|
||||
fn walk_ty(&mut self, t: &'a Ty) {
|
||||
match &t.kind {
|
||||
TyKind::ImplTrait(..) => {
|
||||
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
|
||||
TyKind::ImplTrait(_, bounds) => {
|
||||
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
|
||||
|
||||
// FIXME(precise_capturing): If we were to allow `use` in other positions
|
||||
// (e.g. GATs), then we must validate those as well. However, we don't have
|
||||
// a good way of doing this with the current `Visitor` structure.
|
||||
let mut use_bounds = bounds
|
||||
.iter()
|
||||
.filter_map(|bound| match bound {
|
||||
GenericBound::Use(_, span) => Some(span),
|
||||
_ => None,
|
||||
})
|
||||
.copied();
|
||||
if let Some(bound1) = use_bounds.next()
|
||||
&& let Some(bound2) = use_bounds.next()
|
||||
{
|
||||
self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 });
|
||||
}
|
||||
}
|
||||
TyKind::TraitObject(..) => self
|
||||
.with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| {
|
||||
|
|
@ -244,7 +270,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn dcx(&self) -> &rustc_errors::DiagCtxt {
|
||||
fn dcx(&self) -> DiagCtxtHandle<'a> {
|
||||
self.session.dcx()
|
||||
}
|
||||
|
||||
|
|
@ -365,7 +391,7 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||
self.check_decl_num_args(fn_decl);
|
||||
self.check_decl_cvaradic_pos(fn_decl);
|
||||
self.check_decl_cvariadic_pos(fn_decl);
|
||||
self.check_decl_attrs(fn_decl);
|
||||
self.check_decl_self_param(fn_decl, self_semantic);
|
||||
}
|
||||
|
|
@ -380,13 +406,11 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
|
||||
/// Emits an error if a function declaration has a variadic parameter in the
|
||||
/// beginning or middle of parameter list.
|
||||
/// Example: `fn foo(..., x: i32)` will emit an error.
|
||||
fn check_decl_cvariadic_pos(&self, fn_decl: &FnDecl) {
|
||||
match &*fn_decl.inputs {
|
||||
[Param { ty, span, .. }] => {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
self.dcx().emit_err(errors::FnParamCVarArgsOnly { span: *span });
|
||||
}
|
||||
}
|
||||
[ps @ .., _] => {
|
||||
for Param { ty, span, .. } in ps {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
|
|
@ -432,6 +456,18 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) {
|
||||
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
|
||||
&& (self.extern_mod_safety == Some(Safety::Default)
|
||||
|| !self.features.unsafe_extern_blocks)
|
||||
{
|
||||
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
|
||||
item_span,
|
||||
block: self.current_extern_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -521,7 +557,7 @@ impl<'a> AstValidator<'a> {
|
|||
fn check_foreign_fn_headerless(
|
||||
&self,
|
||||
// Deconstruct to ensure exhaustiveness
|
||||
FnHeader { safety, coroutine_kind, constness, ext }: FnHeader,
|
||||
FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader,
|
||||
) {
|
||||
let report_err = |span| {
|
||||
self.dcx().emit_err(errors::FnQualifierInExtern {
|
||||
|
|
@ -529,10 +565,6 @@ impl<'a> AstValidator<'a> {
|
|||
block: self.current_extern_span(),
|
||||
});
|
||||
};
|
||||
match safety {
|
||||
Safety::Unsafe(span) => report_err(span),
|
||||
Safety::Default => (),
|
||||
}
|
||||
match coroutine_kind {
|
||||
Some(knd) => report_err(knd.span()),
|
||||
None => (),
|
||||
|
|
@ -674,7 +706,7 @@ impl<'a> AstValidator<'a> {
|
|||
let constraint_sugg = data.args.iter().filter_map(|a| match a {
|
||||
AngleBracketedArg::Arg(_) => None,
|
||||
AngleBracketedArg::Constraint(c) => {
|
||||
Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
|
||||
Some(pprust::to_string(|s| s.print_assoc_item_constraint(c)))
|
||||
}
|
||||
});
|
||||
format!(
|
||||
|
|
@ -736,7 +768,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
TyKind::ImplTrait(_, bounds, _) => {
|
||||
TyKind::ImplTrait(_, bounds) => {
|
||||
if self.is_impl_trait_banned {
|
||||
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
|
||||
}
|
||||
|
|
@ -766,11 +798,10 @@ impl<'a> AstValidator<'a> {
|
|||
.span_to_snippet(span)
|
||||
.is_ok_and(|snippet| !snippet.starts_with("#["))
|
||||
{
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
self.lint_buffer.buffer_lint(
|
||||
MISSING_ABI,
|
||||
id,
|
||||
span,
|
||||
fluent::ast_passes_extern_without_abi,
|
||||
BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK),
|
||||
)
|
||||
}
|
||||
|
|
@ -779,11 +810,7 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
/// Checks that generic parameters are in the correct order,
|
||||
/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
|
||||
fn validate_generic_param_order(
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
generics: &[GenericParam],
|
||||
span: Span,
|
||||
) {
|
||||
fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericParam], span: Span) {
|
||||
let mut max_param: Option<ParamKindOrd> = None;
|
||||
let mut out_of_order = FxIndexMap::default();
|
||||
let mut param_idents = Vec::with_capacity(generics.len());
|
||||
|
|
@ -1021,19 +1048,39 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
return; // Avoid visiting again.
|
||||
}
|
||||
ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => {
|
||||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||
self.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
||||
);
|
||||
if let &Safety::Unsafe(span) = safety {
|
||||
self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
|
||||
}
|
||||
if abi.is_none() {
|
||||
self.maybe_lint_missing_abi(item.span, item.id);
|
||||
}
|
||||
visit::walk_item(self, item);
|
||||
self.extern_mod = old_item;
|
||||
self.with_in_extern_mod(*safety, |this| {
|
||||
let old_item = mem::replace(&mut this.extern_mod, Some(item));
|
||||
this.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
||||
);
|
||||
|
||||
if this.features.unsafe_extern_blocks {
|
||||
if &Safety::Default == safety {
|
||||
if item.span.at_least_rust_2024() {
|
||||
this.dcx()
|
||||
.emit_err(errors::MissingUnsafeOnExtern { span: item.span });
|
||||
} else {
|
||||
this.lint_buffer.buffer_lint(
|
||||
MISSING_UNSAFE_ON_EXTERN,
|
||||
item.id,
|
||||
item.span,
|
||||
BuiltinLintDiag::MissingUnsafeOnExtern {
|
||||
suggestion: item.span.shrink_to_lo(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if let &Safety::Unsafe(span) = safety {
|
||||
this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
|
||||
}
|
||||
|
||||
if abi.is_none() {
|
||||
this.maybe_lint_missing_abi(item.span, item.id);
|
||||
}
|
||||
visit::walk_item(this, item);
|
||||
this.extern_mod = old_item;
|
||||
});
|
||||
return; // Avoid visiting again.
|
||||
}
|
||||
ItemKind::Enum(def, _) => {
|
||||
|
|
@ -1165,6 +1212,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
match &fi.kind {
|
||||
ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
|
||||
self.check_foreign_item_safety(fi.span, sig.header.safety);
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(sig.header);
|
||||
|
|
@ -1184,7 +1232,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_foreign_ty_genericless(generics, where_clauses);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability: _, expr }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem { expr, safety, .. }) => {
|
||||
self.check_foreign_item_safety(fi.span, *safety);
|
||||
self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span));
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
|
|
@ -1203,11 +1252,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
for arg in &data.args {
|
||||
match arg {
|
||||
AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
|
||||
// Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
|
||||
// are allowed to contain nested `impl Trait`.
|
||||
// Associated type bindings such as `Item = impl Debug` in
|
||||
// `Iterator<Item = Debug>` are allowed to contain nested `impl Trait`.
|
||||
AngleBracketedArg::Constraint(constraint) => {
|
||||
self.with_impl_trait(None, |this| {
|
||||
this.visit_assoc_constraint(constraint);
|
||||
this.visit_assoc_item_constraint(constraint);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1268,6 +1317,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
GenericBound::Outlives(_) => {}
|
||||
GenericBound::Use(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1286,95 +1336,110 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
||||
if let GenericBound::Trait(poly, modifiers) = bound {
|
||||
match (ctxt, modifiers.constness, modifiers.polarity) {
|
||||
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
|
||||
self.dcx().emit_err(errors::OptionalTraitSupertrait {
|
||||
span: poly.span,
|
||||
path_str: pprust::path_to_string(&poly.trait_ref.path),
|
||||
});
|
||||
match bound {
|
||||
GenericBound::Trait(trait_ref, modifiers) => {
|
||||
match (ctxt, modifiers.constness, modifiers.polarity) {
|
||||
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
|
||||
self.dcx().emit_err(errors::OptionalTraitSupertrait {
|
||||
span: trait_ref.span,
|
||||
path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
|
||||
});
|
||||
}
|
||||
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
|
||||
self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span });
|
||||
}
|
||||
(
|
||||
BoundKind::TraitObject,
|
||||
BoundConstness::Always(_),
|
||||
BoundPolarity::Positive,
|
||||
) => {
|
||||
self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span });
|
||||
}
|
||||
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
|
||||
if let Some(reason) = &self.disallow_tilde_const =>
|
||||
{
|
||||
let reason = match reason {
|
||||
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
|
||||
errors::TildeConstReason::Closure
|
||||
}
|
||||
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
|
||||
errors::TildeConstReason::Function { ident: ident.span }
|
||||
}
|
||||
&DisallowTildeConstContext::Trait(span) => {
|
||||
errors::TildeConstReason::Trait { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImpl(span) => {
|
||||
errors::TildeConstReason::TraitImpl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::Impl(span) => {
|
||||
// FIXME(effects): Consider providing a help message or even a structured
|
||||
// suggestion for moving such bounds to the assoc const fns if available.
|
||||
errors::TildeConstReason::Impl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitImplAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::InherentAssocTy(span) => {
|
||||
errors::TildeConstReason::InherentAssocTy { span }
|
||||
}
|
||||
DisallowTildeConstContext::TraitObject => {
|
||||
errors::TildeConstReason::TraitObject
|
||||
}
|
||||
DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
|
||||
};
|
||||
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
|
||||
}
|
||||
(
|
||||
_,
|
||||
BoundConstness::Always(_) | BoundConstness::Maybe(_),
|
||||
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
|
||||
) => {
|
||||
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
|
||||
span: bound.span(),
|
||||
left: modifiers.constness.as_str(),
|
||||
right: modifiers.polarity.as_str(),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
|
||||
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
|
||||
}
|
||||
(BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
|
||||
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
|
||||
}
|
||||
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
|
||||
if let Some(reason) = &self.disallow_tilde_const =>
|
||||
{
|
||||
let reason = match reason {
|
||||
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
|
||||
errors::TildeConstReason::Closure
|
||||
}
|
||||
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
|
||||
errors::TildeConstReason::Function { ident: ident.span }
|
||||
}
|
||||
&DisallowTildeConstContext::Trait(span) => {
|
||||
errors::TildeConstReason::Trait { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImpl(span) => {
|
||||
errors::TildeConstReason::TraitImpl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::Impl(span) => {
|
||||
// FIXME(effects): Consider providing a help message or even a structured
|
||||
// suggestion for moving such bounds to the assoc const fns if available.
|
||||
errors::TildeConstReason::Impl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitImplAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::InherentAssocTy(span) => {
|
||||
errors::TildeConstReason::InherentAssocTy { span }
|
||||
}
|
||||
DisallowTildeConstContext::TraitObject => {
|
||||
errors::TildeConstReason::TraitObject
|
||||
}
|
||||
DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
|
||||
};
|
||||
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
|
||||
}
|
||||
(
|
||||
_,
|
||||
BoundConstness::Always(_) | BoundConstness::Maybe(_),
|
||||
BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
|
||||
) => {
|
||||
self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
|
||||
span: bound.span(),
|
||||
left: modifiers.constness.as_str(),
|
||||
right: modifiers.polarity.as_str(),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Negative trait bounds are not allowed to have associated constraints
|
||||
if let GenericBound::Trait(trait_ref, modifiers) = bound
|
||||
&& let BoundPolarity::Negative(_) = modifiers.polarity
|
||||
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
||||
{
|
||||
match segment.args.as_deref() {
|
||||
Some(ast::GenericArgs::AngleBracketed(args)) => {
|
||||
for arg in &args.args {
|
||||
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
|
||||
self.dcx().emit_err(errors::ConstraintOnNegativeBound {
|
||||
span: constraint.span,
|
||||
// Negative trait bounds are not allowed to have associated constraints
|
||||
if let BoundPolarity::Negative(_) = modifiers.polarity
|
||||
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
||||
{
|
||||
match segment.args.as_deref() {
|
||||
Some(ast::GenericArgs::AngleBracketed(args)) => {
|
||||
for arg in &args.args {
|
||||
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
|
||||
self.dcx().emit_err(errors::ConstraintOnNegativeBound {
|
||||
span: constraint.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// The lowered form of parenthesized generic args contains an associated type binding.
|
||||
Some(ast::GenericArgs::Parenthesized(args)) => {
|
||||
self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
|
||||
span: args.span,
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
// The lowered form of parenthesized generic args contains a type binding.
|
||||
Some(ast::GenericArgs::Parenthesized(args)) => {
|
||||
self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
|
||||
span: args.span,
|
||||
}
|
||||
GenericBound::Outlives(_) => {}
|
||||
GenericBound::Use(_, span) => match ctxt {
|
||||
BoundKind::Impl => {}
|
||||
BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => {
|
||||
self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere {
|
||||
loc: ctxt.descr(),
|
||||
span: *span,
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
visit::walk_param_bound(self, bound)
|
||||
|
|
@ -1428,17 +1493,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
|
||||
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
|
||||
if let Some(ident) = ident {
|
||||
let msg = match ctxt {
|
||||
FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
|
||||
_ => fluent::ast_passes_pattern_in_bodiless,
|
||||
};
|
||||
let diag = BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident);
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
self.lint_buffer.buffer_lint(
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
id,
|
||||
span,
|
||||
msg,
|
||||
diag,
|
||||
BuiltinLintDiag::PatternsInFnsWithoutBody {
|
||||
span,
|
||||
ident,
|
||||
is_foreign: matches!(ctxt, FnCtxt::Foreign),
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1510,12 +1573,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
Some((right, snippet))
|
||||
}
|
||||
};
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
self.lint_buffer.buffer_lint(
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
item.id,
|
||||
err.span,
|
||||
fluent::ast_passes_deprecated_where_clause_location,
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg),
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1596,11 +1658,13 @@ fn deny_equality_constraints(
|
|||
let len = assoc_path.segments.len() - 1;
|
||||
let gen_args = args.as_deref().cloned();
|
||||
// Build `<Bar = RhsTy>`.
|
||||
let arg = AngleBracketedArg::Constraint(AssocConstraint {
|
||||
let arg = AngleBracketedArg::Constraint(AssocItemConstraint {
|
||||
id: rustc_ast::node_id::DUMMY_NODE_ID,
|
||||
ident: *ident,
|
||||
gen_args,
|
||||
kind: AssocConstraintKind::Equality { term: predicate.rhs_ty.clone().into() },
|
||||
kind: AssocItemConstraintKind::Equality {
|
||||
term: predicate.rhs_ty.clone().into(),
|
||||
},
|
||||
span: ident.span,
|
||||
});
|
||||
// Add `<Bar = RhsTy>` to `Foo`.
|
||||
|
|
@ -1741,6 +1805,7 @@ pub fn check_crate(
|
|||
outer_impl_trait: None,
|
||||
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
|
||||
is_impl_trait_banned: false,
|
||||
extern_mod_safety: None,
|
||||
lint_buffer: lints,
|
||||
};
|
||||
visit::walk_crate(&mut validator, krate);
|
||||
|
|
|
|||
|
|
@ -92,13 +92,6 @@ pub struct FnParamTooMany {
|
|||
pub max_num_args: usize,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_fn_param_c_var_args_only)]
|
||||
pub struct FnParamCVarArgsOnly {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_fn_param_c_var_args_not_last)]
|
||||
pub struct FnParamCVarArgsNotLast {
|
||||
|
|
@ -223,6 +216,15 @@ pub enum ExternBlockSuggestion {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_extern_invalid_safety)]
|
||||
pub struct InvalidSafetyOnExtern {
|
||||
#[primary_span]
|
||||
pub item_span: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub block: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_bound_in_context)]
|
||||
pub struct BoundInContext<'a> {
|
||||
|
|
@ -492,6 +494,13 @@ pub struct UnsafeItem {
|
|||
pub kind: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_missing_unsafe_on_extern)]
|
||||
pub struct MissingUnsafeOnExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_fieldless_union)]
|
||||
pub struct FieldlessUnion {
|
||||
|
|
@ -669,6 +678,7 @@ pub struct ConstAndCVariadic {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_pattern_in_foreign, code = E0130)]
|
||||
// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
|
||||
pub struct PatternInForeign {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
|
|
@ -677,6 +687,7 @@ pub struct PatternInForeign {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_pattern_in_bodiless, code = E0642)]
|
||||
// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
|
||||
pub struct PatternInBodiless {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
|
|
@ -833,3 +844,20 @@ pub struct MatchArmWithNoBody {
|
|||
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_precise_capturing_not_allowed_here)]
|
||||
pub struct PreciseCapturingNotAllowedHere {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub loc: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_precise_capturing_duplicated)]
|
||||
pub struct DuplicatePreciseCapturing {
|
||||
#[primary_span]
|
||||
pub bound1: Span,
|
||||
#[label]
|
||||
pub bound2: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
|
||||
use rustc_ast::{attr, AssocItemConstraint, AssocItemConstraintKind, NodeId};
|
||||
use rustc_ast::{token, PatKind};
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
|
||||
|
|
@ -344,7 +344,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
for predicate in &g.where_clause.predicates {
|
||||
match predicate {
|
||||
ast::WherePredicate::BoundPredicate(bound_pred) => {
|
||||
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
|
||||
// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -445,21 +445,21 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
visit::walk_fn(self, fn_kind)
|
||||
}
|
||||
|
||||
fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
|
||||
if let AssocConstraintKind::Bound { .. } = constraint.kind {
|
||||
if let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref()
|
||||
&& args.inputs.is_empty()
|
||||
&& matches!(args.output, ast::FnRetTy::Default(..))
|
||||
{
|
||||
gate!(
|
||||
&self,
|
||||
return_type_notation,
|
||||
constraint.span,
|
||||
"return type notation is experimental"
|
||||
);
|
||||
}
|
||||
fn visit_assoc_item_constraint(&mut self, constraint: &'a AssocItemConstraint) {
|
||||
if let AssocItemConstraintKind::Bound { .. } = constraint.kind
|
||||
&& let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref()
|
||||
&& args.inputs.is_empty()
|
||||
&& let ast::FnRetTy::Default(..) = args.output
|
||||
{
|
||||
gate!(
|
||||
&self,
|
||||
return_type_notation,
|
||||
constraint.span,
|
||||
"return type notation is experimental"
|
||||
);
|
||||
}
|
||||
visit::walk_assoc_constraint(self, constraint)
|
||||
|
||||
visit::walk_assoc_item_constraint(self, constraint)
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
|
||||
|
|
@ -560,6 +560,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
|
||||
gate_all!(global_registration, "global registration is experimental");
|
||||
gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,15 @@
|
|||
//!
|
||||
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub mod ast_validation;
|
||||
mod errors;
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
|||
self.count += 1;
|
||||
walk_generic_args(self, generic_args)
|
||||
}
|
||||
fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
|
||||
fn visit_assoc_item_constraint(&mut self, constraint: &AssocItemConstraint) {
|
||||
self.count += 1;
|
||||
walk_assoc_constraint(self, constraint)
|
||||
walk_assoc_item_constraint(self, constraint)
|
||||
}
|
||||
fn visit_attribute(&mut self, _attr: &Attribute) {
|
||||
self.count += 1;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use std::str::FromStr;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::visit;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ impl FromStr for Mode {
|
|||
}
|
||||
|
||||
struct ShowSpanVisitor<'a> {
|
||||
dcx: &'a rustc_errors::DiagCtxt,
|
||||
dcx: DiagCtxtHandle<'a>,
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run(dcx: &rustc_errors::DiagCtxt, mode: &str, krate: &ast::Crate) {
|
||||
pub fn run(dcx: DiagCtxtHandle<'_>, mode: &str, krate: &ast::Crate) {
|
||||
let Ok(mode) = mode.parse() else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
mod helpers;
|
||||
pub mod pp;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To
|
|||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Safety};
|
||||
use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
|
||||
use rustc_ast::{GenericArg, GenericBound, SelfKind};
|
||||
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
|
||||
|
|
@ -249,6 +249,7 @@ pub fn print_crate<'a>(
|
|||
let fake_attr = attr::mk_attr_nested_word(
|
||||
g,
|
||||
ast::AttrStyle::Inner,
|
||||
Safety::Default,
|
||||
sym::feature,
|
||||
sym::prelude_import,
|
||||
DUMMY_SP,
|
||||
|
|
@ -259,7 +260,13 @@ pub fn print_crate<'a>(
|
|||
// root, so this is not needed, and actually breaks things.
|
||||
if edition.is_rust_2015() {
|
||||
// `#![no_std]`
|
||||
let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP);
|
||||
let fake_attr = attr::mk_attr_word(
|
||||
g,
|
||||
ast::AttrStyle::Inner,
|
||||
Safety::Default,
|
||||
sym::no_std,
|
||||
DUMMY_SP,
|
||||
);
|
||||
s.print_attribute(&fake_attr);
|
||||
}
|
||||
}
|
||||
|
|
@ -681,22 +688,40 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
}
|
||||
|
||||
// The easiest way to implement token stream pretty printing would be to
|
||||
// print each token followed by a single space. But that would produce ugly
|
||||
// output, so we go to some effort to do better.
|
||||
//
|
||||
// First, we track whether each token that appears in source code is
|
||||
// followed by a space, with `Spacing`, and reproduce that in the output.
|
||||
// This works well in a lot of cases. E.g. `stringify!(x + y)` produces
|
||||
// "x + y" and `stringify!(x+y)` produces "x+y".
|
||||
//
|
||||
// But this doesn't work for code produced by proc macros (which have no
|
||||
// original source text representation) nor for code produced by decl
|
||||
// macros (which are tricky because the whitespace after tokens appearing
|
||||
// in macro rules isn't always what you want in the produced output). For
|
||||
// these we mostly use `Spacing::Alone`, which is the conservative choice.
|
||||
//
|
||||
// So we have a backup mechanism for when `Spacing::Alone` occurs between a
|
||||
// pair of tokens: we check if that pair of tokens can obviously go
|
||||
// together without a space between them. E.g. token `x` followed by token
|
||||
// `,` is better printed as `x,` than `x ,`. (Even if the original source
|
||||
// code was `x ,`.)
|
||||
//
|
||||
// Finally, we must be careful about changing the output. Token pretty
|
||||
// printing is used by `stringify!` and `impl Display for
|
||||
// proc_macro::TokenStream`, and some programs rely on the output having a
|
||||
// particular form, even though they shouldn't. In particular, some proc
|
||||
// macros do `format!({stream})` on a token stream and then "parse" the
|
||||
// output with simple string matching that can't handle whitespace changes.
|
||||
// E.g. we have seen cases where a proc macro can handle `a :: b` but not
|
||||
// `a::b`. See #117433 for some examples.
|
||||
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
||||
let mut iter = tts.trees().peekable();
|
||||
while let Some(tt) = iter.next() {
|
||||
let spacing = self.print_tt(tt, convert_dollar_crate);
|
||||
if let Some(next) = iter.peek() {
|
||||
// Should we print a space after `tt`? There are two guiding
|
||||
// factors.
|
||||
// - `spacing` is the more important and accurate one. Most
|
||||
// tokens have good spacing information, and
|
||||
// `Joint`/`JointHidden` get used a lot.
|
||||
// - `space_between` is the backup. Code produced by proc
|
||||
// macros has worse spacing information, with no
|
||||
// `JointHidden` usage and too much `Alone` usage, which
|
||||
// would result in over-spaced output such as
|
||||
// `( x () , y . z )`. `space_between` avoids some of the
|
||||
// excess whitespace.
|
||||
if spacing == Spacing::Alone && space_between(tt, next) {
|
||||
self.space();
|
||||
}
|
||||
|
|
@ -852,18 +877,11 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
|
||||
fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
|
||||
match nt {
|
||||
token::NtExpr(e) => self.expr_to_string(e),
|
||||
token::NtMeta(e) => self.attr_item_to_string(e),
|
||||
token::NtTy(e) => self.ty_to_string(e),
|
||||
token::NtPath(e) => self.path_to_string(e),
|
||||
token::NtItem(e) => self.item_to_string(e),
|
||||
token::NtBlock(e) => self.block_to_string(e),
|
||||
token::NtStmt(e) => self.stmt_to_string(e),
|
||||
token::NtPat(e) => self.pat_to_string(e),
|
||||
token::NtLiteral(e) => self.expr_to_string(e),
|
||||
token::NtVis(e) => self.vis_to_string(e),
|
||||
}
|
||||
// We extract the token stream from the AST fragment and pretty print
|
||||
// it, rather than using AST pretty printing, because `Nonterminal` is
|
||||
// slated for removal in #124141. (This method will also then be
|
||||
// removed.)
|
||||
self.tts_to_string(&TokenStream::from_nonterminal_ast(nt))
|
||||
}
|
||||
|
||||
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
|
||||
|
|
@ -997,6 +1015,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
|
||||
}
|
||||
|
||||
fn tts_to_string(&self, tokens: &TokenStream) -> String {
|
||||
Self::to_string(|s| s.print_tts(tokens, false))
|
||||
}
|
||||
|
||||
fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
|
||||
let mut printer = State::new();
|
||||
f(&mut printer);
|
||||
|
|
@ -1027,7 +1049,7 @@ impl<'a> PrintState<'a> for State<'a> {
|
|||
self.word("<");
|
||||
self.commasep(Inconsistent, &data.args, |s, arg| match arg {
|
||||
ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
|
||||
ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
|
||||
ast::AngleBracketedArg::Constraint(c) => s.print_assoc_item_constraint(c),
|
||||
});
|
||||
self.word(">")
|
||||
}
|
||||
|
|
@ -1079,21 +1101,21 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
|
||||
pub fn print_assoc_item_constraint(&mut self, constraint: &ast::AssocItemConstraint) {
|
||||
self.print_ident(constraint.ident);
|
||||
if let Some(args) = constraint.gen_args.as_ref() {
|
||||
self.print_generic_args(args, false)
|
||||
}
|
||||
self.space();
|
||||
match &constraint.kind {
|
||||
ast::AssocConstraintKind::Equality { term } => {
|
||||
ast::AssocItemConstraintKind::Equality { term } => {
|
||||
self.word_space("=");
|
||||
match term {
|
||||
Term::Ty(ty) => self.print_type(ty),
|
||||
Term::Const(c) => self.print_expr_anon_const(c, &[]),
|
||||
}
|
||||
}
|
||||
ast::AssocConstraintKind::Bound { bounds } => {
|
||||
ast::AssocItemConstraintKind::Bound { bounds } => {
|
||||
if !bounds.is_empty() {
|
||||
self.word_nbsp(":");
|
||||
self.print_type_bounds(bounds);
|
||||
|
|
@ -1165,17 +1187,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_type_bounds(bounds);
|
||||
}
|
||||
ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => {
|
||||
ast::TyKind::ImplTrait(_, bounds) => {
|
||||
self.word_nbsp("impl");
|
||||
if let Some((precise_capturing_args, ..)) = precise_capturing_args.as_deref() {
|
||||
self.word("use");
|
||||
self.word("<");
|
||||
self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg {
|
||||
ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
|
||||
ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
|
||||
});
|
||||
self.word(">")
|
||||
}
|
||||
self.print_type_bounds(bounds);
|
||||
}
|
||||
ast::TyKind::Array(ty, length) => {
|
||||
|
|
@ -1778,6 +1791,15 @@ impl<'a> State<'a> {
|
|||
self.print_poly_trait_ref(tref);
|
||||
}
|
||||
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
|
||||
GenericBound::Use(args, _) => {
|
||||
self.word("use");
|
||||
self.word("<");
|
||||
self.commasep(Inconsistent, args, |s, arg| match arg {
|
||||
ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
|
||||
ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
|
||||
});
|
||||
self.word(">")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1955,6 +1977,7 @@ impl<'a> State<'a> {
|
|||
fn print_safety(&mut self, s: ast::Safety) {
|
||||
match s {
|
||||
ast::Safety::Default => {}
|
||||
ast::Safety::Safe(_) => self.word_nbsp("safe"),
|
||||
ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"),
|
||||
}
|
||||
}
|
||||
|
|
@ -2042,10 +2065,6 @@ impl<'a> State<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn tts_to_string(&self, tokens: &TokenStream) -> String {
|
||||
Self::to_string(|s| s.print_tts(tokens, false))
|
||||
}
|
||||
|
||||
pub(crate) fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
|
||||
Self::to_string(|s| s.print_path_segment(p, false))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@ use rustc_ast::ptr::P;
|
|||
use rustc_ast::ModKind;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
||||
enum DelegationKind<'a> {
|
||||
Single,
|
||||
List(&'a [(Ident, Option<Ident>)]),
|
||||
Glob,
|
||||
}
|
||||
|
||||
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
|
||||
format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
|
||||
}
|
||||
|
|
@ -31,7 +37,13 @@ impl<'a> State<'a> {
|
|||
ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
}
|
||||
ast::ForeignItemKind::Static(box ast::StaticForeignItem { ty, mutability, expr }) => {
|
||||
ast::ForeignItemKind::Static(box ast::StaticForeignItem {
|
||||
ty,
|
||||
mutability,
|
||||
expr,
|
||||
safety,
|
||||
}) => {
|
||||
self.print_safety(*safety);
|
||||
self.print_item_const(
|
||||
ident,
|
||||
Some(*mutability),
|
||||
|
|
@ -165,7 +177,8 @@ impl<'a> State<'a> {
|
|||
self.print_use_tree(tree);
|
||||
self.word(";");
|
||||
}
|
||||
ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => {
|
||||
ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => {
|
||||
self.print_safety(*safety);
|
||||
self.print_item_const(
|
||||
item.ident,
|
||||
Some(*mutbl),
|
||||
|
|
@ -380,7 +393,7 @@ impl<'a> State<'a> {
|
|||
&item.vis,
|
||||
&deleg.qself,
|
||||
&deleg.path,
|
||||
None,
|
||||
DelegationKind::Single,
|
||||
&deleg.body,
|
||||
),
|
||||
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
|
||||
|
|
@ -388,7 +401,7 @@ impl<'a> State<'a> {
|
|||
&item.vis,
|
||||
&deleg.qself,
|
||||
&deleg.prefix,
|
||||
Some(&deleg.suffixes),
|
||||
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
|
||||
&deleg.body,
|
||||
),
|
||||
}
|
||||
|
|
@ -572,7 +585,7 @@ impl<'a> State<'a> {
|
|||
vis,
|
||||
&deleg.qself,
|
||||
&deleg.path,
|
||||
None,
|
||||
DelegationKind::Single,
|
||||
&deleg.body,
|
||||
),
|
||||
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
|
||||
|
|
@ -580,20 +593,20 @@ impl<'a> State<'a> {
|
|||
vis,
|
||||
&deleg.qself,
|
||||
&deleg.prefix,
|
||||
Some(&deleg.suffixes),
|
||||
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
|
||||
&deleg.body,
|
||||
),
|
||||
}
|
||||
self.ann.post(self, AnnNode::SubItem(id))
|
||||
}
|
||||
|
||||
pub(crate) fn print_delegation(
|
||||
fn print_delegation(
|
||||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
vis: &ast::Visibility,
|
||||
qself: &Option<P<ast::QSelf>>,
|
||||
path: &ast::Path,
|
||||
suffixes: Option<&[(Ident, Option<Ident>)]>,
|
||||
kind: DelegationKind<'_>,
|
||||
body: &Option<P<ast::Block>>,
|
||||
) {
|
||||
if body.is_some() {
|
||||
|
|
@ -607,21 +620,28 @@ impl<'a> State<'a> {
|
|||
} else {
|
||||
self.print_path(path, false, 0);
|
||||
}
|
||||
if let Some(suffixes) = suffixes {
|
||||
self.word("::");
|
||||
self.word("{");
|
||||
for (i, (ident, rename)) in suffixes.iter().enumerate() {
|
||||
self.print_ident(*ident);
|
||||
if let Some(rename) = rename {
|
||||
self.nbsp();
|
||||
self.word_nbsp("as");
|
||||
self.print_ident(*rename);
|
||||
}
|
||||
if i != suffixes.len() - 1 {
|
||||
self.word_space(",");
|
||||
match kind {
|
||||
DelegationKind::Single => {}
|
||||
DelegationKind::List(suffixes) => {
|
||||
self.word("::");
|
||||
self.word("{");
|
||||
for (i, (ident, rename)) in suffixes.iter().enumerate() {
|
||||
self.print_ident(*ident);
|
||||
if let Some(rename) = rename {
|
||||
self.nbsp();
|
||||
self.word_nbsp("as");
|
||||
self.print_ident(*rename);
|
||||
}
|
||||
if i != suffixes.len() - 1 {
|
||||
self.word_space(",");
|
||||
}
|
||||
}
|
||||
self.word("}");
|
||||
}
|
||||
DelegationKind::Glob => {
|
||||
self.word("::");
|
||||
self.word("*");
|
||||
}
|
||||
self.word("}");
|
||||
}
|
||||
if let Some(body) = body {
|
||||
self.nbsp();
|
||||
|
|
|
|||
|
|
@ -528,15 +528,10 @@ pub fn cfg_matches(
|
|||
try_gate_cfg(cfg.name, cfg.span, sess, features);
|
||||
match sess.psess.check_config.expecteds.get(&cfg.name) {
|
||||
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
sess.psess.buffer_lint(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
if let Some(value) = cfg.value {
|
||||
format!("unexpected `cfg` condition value: `{value}`")
|
||||
} else {
|
||||
format!("unexpected `cfg` condition value: (none)")
|
||||
},
|
||||
BuiltinLintDiag::UnexpectedCfgValue(
|
||||
(cfg.name, cfg.name_span),
|
||||
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||
|
|
@ -544,11 +539,10 @@ pub fn cfg_matches(
|
|||
);
|
||||
}
|
||||
None if sess.psess.check_config.exhaustive_names => {
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
sess.psess.buffer_lint(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
format!("unexpected `cfg` condition name: `{}`", cfg.name),
|
||||
BuiltinLintDiag::UnexpectedCfgName(
|
||||
(cfg.name, cfg.name_span),
|
||||
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||
|
|
@ -602,7 +596,7 @@ pub fn eval_condition(
|
|||
features: Option<&Features>,
|
||||
eval: &mut impl FnMut(Condition) -> bool,
|
||||
) -> bool {
|
||||
let dcx = &sess.psess.dcx;
|
||||
let dcx = sess.dcx();
|
||||
match &cfg.kind {
|
||||
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
|
||||
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@
|
|||
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
|
||||
//! to this crate.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
mod builtin;
|
||||
mod session_diagnostics;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::{codes::*, Applicability, Diag, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ pub(crate) struct UnknownMetaItem<'a> {
|
|||
|
||||
// Manual implementation to be able to format `expected` items correctly.
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> {
|
||||
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
|
||||
Diag::new(dcx, level, fluent::attr_unknown_meta_item)
|
||||
.with_span(self.span)
|
||||
|
|
@ -202,7 +203,7 @@ pub(crate) struct UnsupportedLiteral {
|
|||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
|
||||
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
let mut diag = Diag::new(
|
||||
dcx,
|
||||
level,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ icu_list = "1.2"
|
|||
icu_locid = "1.2"
|
||||
icu_locid_transform = "1.3.2"
|
||||
icu_provider = "1.2"
|
||||
icu_provider_adapters = "1.2"
|
||||
zerovec = "0.10.0"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@
|
|||
//! --cldr-tag latest --icuexport-tag latest -o src/data
|
||||
//! ```
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
// tidy-alphabetical-start
|
||||
#![allow(elided_lifetimes_in_paths)]
|
||||
#![allow(internal_features)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
mod data {
|
||||
include!("data/mod.rs");
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxt};
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
pub fn dcx(&self) -> &'tcx DiagCtxt {
|
||||
pub fn dcx(&self) -> DiagCtxtHandle<'tcx> {
|
||||
self.infcx.dcx()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use crate::type_check::Locations;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
|
||||
use rustc_span::Span;
|
||||
use std::fmt;
|
||||
use std::ops::Index;
|
||||
|
||||
use crate::type_check::Locations;
|
||||
|
||||
pub(crate) mod graph;
|
||||
|
||||
/// A set of NLL region constraints. These include "outlives"
|
||||
|
|
@ -45,18 +43,6 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
|
|||
graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars)
|
||||
}
|
||||
|
||||
/// Computes cycles (SCCs) in the graph of regions. In particular,
|
||||
/// find all regions R1, R2 such that R1: R2 and R2: R1 and group
|
||||
/// them into an SCC, and find the relationships between SCCs.
|
||||
pub(crate) fn compute_sccs(
|
||||
&self,
|
||||
constraint_graph: &graph::NormalConstraintGraph,
|
||||
static_region: RegionVid,
|
||||
) -> Sccs<RegionVid, ConstraintSccIndex> {
|
||||
let region_graph = &constraint_graph.region_graph(self, static_region);
|
||||
Sccs::new(region_graph)
|
||||
}
|
||||
|
||||
pub(crate) fn outlives(
|
||||
&self,
|
||||
) -> &IndexSlice<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
|
||||
|
|
@ -97,7 +83,7 @@ pub struct OutlivesConstraint<'tcx> {
|
|||
pub category: ConstraintCategory<'tcx>,
|
||||
|
||||
/// Variance diagnostic information
|
||||
pub variance_info: VarianceDiagInfo<'tcx>,
|
||||
pub variance_info: VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
|
||||
/// If this constraint is promoted from closure requirements.
|
||||
pub from_closure: bool,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_errors::Diag;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc_infer::infer::region_constraints::Constraint;
|
||||
|
|
@ -241,7 +242,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
|||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
type_op_prove_predicate_with_cause(&ocx, key, cause);
|
||||
try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
|
||||
try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,7 +288,7 @@ where
|
|||
let (param_env, value) = key.into_parts();
|
||||
let _ = ocx.normalize(&cause, param_env, value.value);
|
||||
|
||||
try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
|
||||
try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,7 +319,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
|||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
|
||||
try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
|
||||
try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -342,6 +343,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
|||
) -> Option<Diag<'tcx>> {
|
||||
try_extract_error_from_region_constraints(
|
||||
mbcx.infcx,
|
||||
mbcx.mir_def_id(),
|
||||
placeholder_region,
|
||||
error_region,
|
||||
self.region_constraints.as_ref().unwrap(),
|
||||
|
|
@ -358,6 +360,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
|||
#[instrument(skip(ocx), level = "debug")]
|
||||
fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
generic_param_scope: LocalDefId,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<Diag<'tcx>> {
|
||||
|
|
@ -368,6 +371,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
|||
let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
|
||||
try_extract_error_from_region_constraints(
|
||||
ocx.infcx,
|
||||
generic_param_scope,
|
||||
placeholder_region,
|
||||
error_region,
|
||||
®ion_constraints,
|
||||
|
|
@ -379,6 +383,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
|||
#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
|
||||
fn try_extract_error_from_region_constraints<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
generic_param_scope: LocalDefId,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
region_constraints: &RegionConstraintData<'tcx>,
|
||||
|
|
@ -452,15 +457,18 @@ fn try_extract_error_from_region_constraints<'tcx>(
|
|||
RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
|
||||
}
|
||||
};
|
||||
NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| {
|
||||
if let SubregionOrigin::Subtype(trace) = cause {
|
||||
Some(
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
NiceRegionError::new(&infcx.err_ctxt(), generic_param_scope, error)
|
||||
.try_report_from_nll()
|
||||
.or_else(|| {
|
||||
if let SubregionOrigin::Subtype(trace) = cause {
|
||||
Some(
|
||||
infcx.err_ctxt().report_and_explain_type_error(
|
||||
*trace,
|
||||
TypeError::RegionsPlaceholderMismatch,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,12 +100,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
move_site_vec.iter().map(|move_site| move_site.moi).collect();
|
||||
|
||||
if move_out_indices.is_empty() {
|
||||
let root_place = PlaceRef { projection: &[], ..used_place };
|
||||
let root_local = used_place.local;
|
||||
|
||||
if !self.uninitialized_error_reported.insert(root_place) {
|
||||
if !self.uninitialized_error_reported.insert(root_local) {
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
|
||||
root_place
|
||||
root_local
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
seen_spans.insert(move_span);
|
||||
}
|
||||
|
||||
use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
|
||||
use_spans.var_path_only_subdiag(&mut err, desired_action);
|
||||
|
||||
if !is_loop_move {
|
||||
err.span_label(
|
||||
|
|
@ -284,7 +284,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
|
||||
&& let ty::Param(_) = self_ty.kind()
|
||||
&& ty == self_ty
|
||||
&& Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait()
|
||||
&& self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce)
|
||||
{
|
||||
// this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`.
|
||||
true
|
||||
|
|
@ -303,24 +303,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if needs_note {
|
||||
if let Some(local) = place.as_local() {
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
});
|
||||
} else {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -399,8 +393,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
let hir = self.infcx.tcx.hir();
|
||||
if let Some(body_id) = hir.maybe_body_owned_by(self.mir_def_id()) {
|
||||
let expr = hir.body(body_id).value;
|
||||
if let Some(body) = hir.maybe_body_owned_by(self.mir_def_id()) {
|
||||
let expr = body.value;
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span);
|
||||
let mut finder = ExpressionFinder {
|
||||
|
|
@ -556,11 +550,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// We use the statements were the binding was initialized, and inspect the HIR to look
|
||||
// for the branching codepaths that aren't covered, to point at them.
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body_id = map.body_owned_by(self.mir_def_id());
|
||||
let body = map.body(body_id);
|
||||
|
||||
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
|
||||
visitor.visit_body(body);
|
||||
let body = map.body_owned_by(self.mir_def_id());
|
||||
let mut visitor =
|
||||
ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
|
||||
visitor.visit_body(&body);
|
||||
|
||||
let mut show_assign_sugg = false;
|
||||
let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
|
||||
|
|
@ -598,7 +591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
E0381,
|
||||
"{used} binding {desc}{isnt_initialized}"
|
||||
);
|
||||
use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
|
||||
use_spans.var_path_only_subdiag(&mut err, desired_action);
|
||||
|
||||
if let InitializationRequiringAction::PartialAssignment
|
||||
| InitializationRequiringAction::Assignment = desired_action
|
||||
|
|
@ -652,7 +645,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
// FIXME: We make sure that this is a normal top-level binding,
|
||||
// but we could suggest `todo!()` for all uninitialized bindings in the pattern pattern
|
||||
// but we could suggest `todo!()` for all uninitialized bindings in the pattern
|
||||
if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =
|
||||
&ex.kind
|
||||
&& let hir::PatKind::Binding(..) = pat.kind
|
||||
|
|
@ -665,7 +658,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
let mut visitor = LetVisitor { decl_span, sugg_span: None };
|
||||
visitor.visit_body(body);
|
||||
visitor.visit_body(&body);
|
||||
if let Some(span) = visitor.sugg_span {
|
||||
self.suggest_assign_value(&mut err, moved_place, span);
|
||||
}
|
||||
|
|
@ -709,9 +702,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
|
||||
&& pred.self_ty() == ty
|
||||
{
|
||||
if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
|
||||
if tcx.is_lang_item(pred.def_id(), LangItem::Fn) {
|
||||
return Some(hir::Mutability::Not);
|
||||
} else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
|
||||
} else if tcx.is_lang_item(pred.def_id(), LangItem::FnMut) {
|
||||
return Some(hir::Mutability::Mut);
|
||||
}
|
||||
}
|
||||
|
|
@ -997,7 +990,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
expr: &'cx hir::Expr<'cx>,
|
||||
expr: &hir::Expr<'_>,
|
||||
) {
|
||||
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return };
|
||||
|
|
@ -1085,8 +1078,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
mut expr: &'cx hir::Expr<'cx>,
|
||||
mut other_expr: Option<&'cx hir::Expr<'cx>>,
|
||||
mut expr: &'tcx hir::Expr<'tcx>,
|
||||
mut other_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
use_spans: Option<UseSpans<'tcx>>,
|
||||
) {
|
||||
if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
|
||||
|
|
@ -1348,7 +1341,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return;
|
||||
};
|
||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||
let ocx = ObligationCtxt::new(self.infcx);
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);
|
||||
let cause = ObligationCause::misc(span, self.mir_def_id());
|
||||
|
||||
ocx.register_bound(cause, self.param_env, ty, def_id);
|
||||
|
|
@ -1362,7 +1355,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match *predicate.self_ty().kind() {
|
||||
ty::Param(param_ty) => Ok((
|
||||
generics.type_param(param_ty, tcx),
|
||||
predicate.trait_ref.print_only_trait_path().to_string(),
|
||||
predicate.trait_ref.print_trait_sugared().to_string(),
|
||||
)),
|
||||
_ => Err(()),
|
||||
}
|
||||
|
|
@ -1411,13 +1404,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&value_msg,
|
||||
);
|
||||
|
||||
borrow_spans.var_path_only_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
crate::InitializationRequiringAction::Borrow,
|
||||
);
|
||||
borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
|
||||
|
||||
move_spans.var_subdiag(self.dcx(), &mut err, None, |kind, var_span| {
|
||||
move_spans.var_subdiag(&mut err, None, |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
|
||||
|
|
@ -1469,7 +1458,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
borrow_span,
|
||||
&self.describe_any_place(borrow.borrowed_place.as_ref()),
|
||||
);
|
||||
borrow_spans.var_subdiag(self.dcx(), &mut err, Some(borrow.kind), |kind, var_span| {
|
||||
borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
let place = &borrow.borrowed_place;
|
||||
let desc_place = self.describe_any_place(place.as_ref());
|
||||
|
|
@ -1634,7 +1623,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"mutably borrow",
|
||||
);
|
||||
borrow_spans.var_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),
|
||||
|kind, var_span| {
|
||||
|
|
@ -1731,64 +1719,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
if issued_spans == borrow_spans {
|
||||
borrow_spans.var_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(gen_borrow_kind),
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUsePlaceClosure {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
}
|
||||
}
|
||||
borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
issued_spans.var_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(issued_borrow.kind),
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
let borrow_place = &issued_borrow.borrowed_place;
|
||||
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
|
||||
}
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }
|
||||
}
|
||||
issued_spans.var_subdiag(&mut err, Some(issued_borrow.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
let borrow_place = &issued_borrow.borrowed_place;
|
||||
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
|
||||
}
|
||||
},
|
||||
);
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
borrow_spans.var_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(gen_borrow_kind),
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }
|
||||
}
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
SecondBorrowUsePlaceClosure { place: desc_place, var_span }
|
||||
}
|
||||
borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }
|
||||
}
|
||||
},
|
||||
);
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
SecondBorrowUsePlaceClosure { place: desc_place, var_span }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if union_type_name != "" {
|
||||
|
|
@ -1833,7 +1802,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let hir::ExprKind::MethodCall(..) = ex.kind
|
||||
&& let Some(method_def_id) =
|
||||
self.typeck_results.type_dependent_def_id(ex.hir_id)
|
||||
&& self.tcx.lang_items().clone_trait() == Some(self.tcx.parent(method_def_id))
|
||||
&& self.tcx.is_lang_item(self.tcx.parent(method_def_id), LangItem::Clone)
|
||||
{
|
||||
self.clones.push(ex);
|
||||
}
|
||||
|
|
@ -2017,7 +1986,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> {
|
||||
pub(crate) fn find_expr(&self, span: Span) -> Option<&'tcx hir::Expr<'tcx>> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?;
|
||||
let mut expr_finder = FindExprBySpan::new(span, tcx);
|
||||
|
|
@ -2889,7 +2858,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
..
|
||||
} = explanation
|
||||
{
|
||||
if let Some(diag) = self.try_report_cannot_return_reference_to_local(
|
||||
if let Err(diag) = self.try_report_cannot_return_reference_to_local(
|
||||
borrow,
|
||||
borrow_span,
|
||||
span,
|
||||
|
|
@ -2962,7 +2931,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
err.span_label(borrow_span, "borrowed value does not live long enough");
|
||||
err.span_label(drop_span, format!("`{name}` dropped here while still borrowed"));
|
||||
|
||||
borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
is_within: borrow_spans.for_coroutine(),
|
||||
args_span,
|
||||
|
|
@ -3076,7 +3045,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
|
||||
explanation
|
||||
{
|
||||
if let Some(diag) = self.try_report_cannot_return_reference_to_local(
|
||||
if let Err(diag) = self.try_report_cannot_return_reference_to_local(
|
||||
borrow,
|
||||
proper_span,
|
||||
span,
|
||||
|
|
@ -3160,8 +3129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let is_format_arguments_item = if let Some(expr_ty) = expr_ty
|
||||
&& let ty::Adt(adt, _) = expr_ty.kind()
|
||||
{
|
||||
self.infcx.tcx.lang_items().get(LangItem::FormatArguments)
|
||||
== Some(adt.did())
|
||||
self.infcx.tcx.is_lang_item(adt.did(), LangItem::FormatArguments)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
|
@ -3221,7 +3189,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
None,
|
||||
);
|
||||
|
||||
borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
is_within: borrow_spans.for_coroutine(),
|
||||
args_span,
|
||||
|
|
@ -3238,11 +3206,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return_span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
opt_place_desc: Option<&String>,
|
||||
) -> Option<Diag<'tcx>> {
|
||||
) -> Result<(), Diag<'tcx>> {
|
||||
let return_kind = match category {
|
||||
ConstraintCategory::Return(_) => "return",
|
||||
ConstraintCategory::Yield => "yield",
|
||||
_ => return None,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
// FIXME use a better heuristic than Spans
|
||||
|
|
@ -3318,7 +3286,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Some(err)
|
||||
Err(err)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -3343,6 +3311,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
} else if string.starts_with("gen") {
|
||||
// `gen` is 3 chars long
|
||||
Some(3)
|
||||
} else if string.starts_with("static") {
|
||||
// `static` is 6 chars long
|
||||
// This is used for `!Unpin` coroutines
|
||||
Some(6)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -3678,7 +3650,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"assign",
|
||||
);
|
||||
|
||||
loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
|
||||
loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
|
|
@ -3696,7 +3668,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
|
||||
|
||||
loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
|
||||
loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
|
|
@ -4369,13 +4341,14 @@ impl<'hir> Visitor<'hir> for BreakFinder {
|
|||
|
||||
/// Given a set of spans representing statements initializing the relevant binding, visit all the
|
||||
/// function expressions looking for branching code paths that *do not* initialize the binding.
|
||||
struct ConditionVisitor<'b> {
|
||||
struct ConditionVisitor<'b, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
spans: &'b [Span],
|
||||
name: &'b str,
|
||||
errors: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
||||
impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||
match ex.kind {
|
||||
hir::ExprKind::If(cond, body, None) => {
|
||||
|
|
@ -4461,6 +4434,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
|||
),
|
||||
));
|
||||
} else if let Some(guard) = &arm.guard {
|
||||
if matches!(
|
||||
self.tcx.hir_node(arm.body.hir_id),
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
self.errors.push((
|
||||
arm.pat.span.to(guard.span),
|
||||
format!(
|
||||
|
|
@ -4470,6 +4449,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
|||
),
|
||||
));
|
||||
} else {
|
||||
if matches!(
|
||||
self.tcx.hir_node(arm.body.hir_id),
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
self.errors.push((
|
||||
arm.pat.span,
|
||||
format!(
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ use crate::session_diagnostics::{
|
|||
CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
|
||||
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
|
||||
};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_errors::{DiagCtxt, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::CoroutineKind;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::BoundRegionConversionTime;
|
||||
use rustc_infer::traits::{FulfillmentErrorCode, SelectionError};
|
||||
use rustc_infer::traits::SelectionError;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
|
|
@ -29,7 +29,9 @@ use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
|
|||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
|
||||
use rustc_trait_selection::traits::{
|
||||
type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode,
|
||||
};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
|
|
@ -114,7 +116,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
{
|
||||
if let ty::FnDef(id, _) = *const_.ty().kind() {
|
||||
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
||||
if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
|
||||
if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
|
||||
let closure = match args.first() {
|
||||
Some(Spanned {
|
||||
node: Operand::Copy(place) | Operand::Move(place), ..
|
||||
|
|
@ -128,16 +130,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.subdiagnostic(
|
||||
self.dcx(),
|
||||
OnClosureNote::InvokedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(
|
||||
self.infcx.tcx,
|
||||
hir_place,
|
||||
),
|
||||
span: *span,
|
||||
},
|
||||
);
|
||||
diag.subdiagnostic(OnClosureNote::InvokedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(
|
||||
self.infcx.tcx,
|
||||
hir_place,
|
||||
),
|
||||
span: *span,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -150,13 +149,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.subdiagnostic(
|
||||
self.dcx(),
|
||||
OnClosureNote::MovedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
span: *span,
|
||||
},
|
||||
);
|
||||
diag.subdiagnostic(OnClosureNote::MovedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
span: *span,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -589,14 +585,9 @@ impl UseSpans<'_> {
|
|||
|
||||
/// Add a span label to the arguments of the closure, if it exists.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn args_subdiag(
|
||||
self,
|
||||
dcx: &DiagCtxt,
|
||||
err: &mut Diag<'_>,
|
||||
f: impl FnOnce(Span) -> CaptureArgLabel,
|
||||
) {
|
||||
pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
|
||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||
err.subdiagnostic(dcx, f(args_span));
|
||||
err.subdiagnostic(f(args_span));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -605,7 +596,6 @@ impl UseSpans<'_> {
|
|||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_path_only_subdiag(
|
||||
self,
|
||||
dcx: &DiagCtxt,
|
||||
err: &mut Diag<'_>,
|
||||
action: crate::InitializationRequiringAction,
|
||||
) {
|
||||
|
|
@ -614,26 +604,20 @@ impl UseSpans<'_> {
|
|||
if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
|
||||
match closure_kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
Assignment => AssignInCoroutine { path_span },
|
||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
Assignment => AssignInCoroutine { path_span },
|
||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
});
|
||||
}
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
Assignment => AssignInClosure { path_span },
|
||||
PartialAssignment => AssignPartInClosure { path_span },
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
Assignment => AssignInClosure { path_span },
|
||||
PartialAssignment => AssignPartInClosure { path_span },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -643,32 +627,28 @@ impl UseSpans<'_> {
|
|||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_subdiag(
|
||||
self,
|
||||
dcx: &DiagCtxt,
|
||||
err: &mut Diag<'_>,
|
||||
kind: Option<rustc_middle::mir::BorrowKind>,
|
||||
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
||||
) {
|
||||
if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
|
||||
if capture_kind_span != path_span {
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Fake(_) => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
err.subdiagnostic(match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Fake(_) => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
|
||||
rustc_middle::mir::BorrowKind::Mut { .. } => {
|
||||
CaptureVarKind::Mut { kind_span: capture_kind_span }
|
||||
}
|
||||
},
|
||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
rustc_middle::mir::BorrowKind::Mut { .. } => {
|
||||
CaptureVarKind::Mut { kind_span: capture_kind_span }
|
||||
}
|
||||
},
|
||||
);
|
||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
});
|
||||
};
|
||||
let diag = f(closure_kind, path_span);
|
||||
err.subdiagnostic(dcx, diag);
|
||||
err.subdiagnostic(diag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -765,13 +745,12 @@ impl<'tcx> BorrowedContentSource<'tcx> {
|
|||
ty::FnDef(def_id, args) => {
|
||||
let trait_id = tcx.trait_of_item(def_id)?;
|
||||
|
||||
let lang_items = tcx.lang_items();
|
||||
if Some(trait_id) == lang_items.deref_trait()
|
||||
|| Some(trait_id) == lang_items.deref_mut_trait()
|
||||
if tcx.is_lang_item(trait_id, LangItem::Deref)
|
||||
|| tcx.is_lang_item(trait_id, LangItem::DerefMut)
|
||||
{
|
||||
Some(BorrowedContentSource::OverloadedDeref(args.type_at(0)))
|
||||
} else if Some(trait_id) == lang_items.index_trait()
|
||||
|| Some(trait_id) == lang_items.index_mut_trait()
|
||||
} else if tcx.is_lang_item(trait_id, LangItem::Index)
|
||||
|| tcx.is_lang_item(trait_id, LangItem::IndexMut)
|
||||
{
|
||||
Some(BorrowedContentSource::OverloadedIndex(args.type_at(0)))
|
||||
} else {
|
||||
|
|
@ -1039,17 +1018,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.unwrap_or_else(|| "value".to_owned());
|
||||
match kind {
|
||||
CallKind::FnCall { fn_trait_id, self_ty }
|
||||
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
||||
if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) =>
|
||||
{
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::Call {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonLabel::Call {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
// Check if the move occurs on a value because of a call on a closure that comes
|
||||
// from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`:
|
||||
// ```
|
||||
|
|
@ -1118,27 +1094,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
|
||||
} else {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonNote::FnOnceMoveInCall { var_span },
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||
}
|
||||
}
|
||||
CallKind::Operator { self_arg, trait_id, .. } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::OperatorUse {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonLabel::OperatorUse {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
let lang = self.infcx.tcx.lang_items();
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
|
||||
.contains(&Some(trait_id))
|
||||
{
|
||||
|
|
@ -1163,14 +1132,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
|
||||
let func = tcx.def_path_str(method_did);
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonNote::FuncTakeSelf {
|
||||
func,
|
||||
place_name: place_name.clone(),
|
||||
span: self_arg.span,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
|
||||
func,
|
||||
place_name: place_name.clone(),
|
||||
span: self_arg.span,
|
||||
});
|
||||
}
|
||||
let parent_did = tcx.parent(method_did);
|
||||
let parent_self_ty =
|
||||
|
|
@ -1184,10 +1150,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
});
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::BorrowContent { var_span },
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
|
||||
}
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
let ty = moved_place.ty(self.body, tcx).ty;
|
||||
|
|
@ -1201,24 +1164,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
_ => false,
|
||||
};
|
||||
if suggest {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonSuggest::IterateSlice {
|
||||
ty,
|
||||
span: move_span.shrink_to_lo(),
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
|
||||
ty,
|
||||
span: move_span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::ImplicitCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
// If the moved place was a `&mut` ref, then we can
|
||||
// suggest to reborrow it where it was moved, so it
|
||||
// will still be valid by the time we get to the usage.
|
||||
|
|
@ -1242,31 +1199,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
if let Some((CallDesugaringKind::Await, _)) = desugaring {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::Await {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonLabel::Await {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
} else {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::MethodCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonLabel::MethodCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
}
|
||||
// Erase and shadow everything that could be passed to the new infcx.
|
||||
let ty = moved_place.ty(self.body, tcx).ty;
|
||||
|
||||
if let ty::Adt(def, args) = ty.peel_refs().kind()
|
||||
&& Some(def.did()) == tcx.lang_items().pin_type()
|
||||
&& tcx.is_lang_item(def.did(), LangItem::Pin)
|
||||
&& let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind()
|
||||
&& let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
fn_call_span,
|
||||
|
|
@ -1275,12 +1226,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
)
|
||||
&& self.infcx.can_eq(self.param_env, ty, self_ty)
|
||||
{
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonSuggest::FreshReborrow {
|
||||
span: move_span.shrink_to_hi(),
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {
|
||||
span: move_span.shrink_to_hi(),
|
||||
});
|
||||
has_sugg = true;
|
||||
}
|
||||
if let Some(clone_trait) = tcx.lang_items().clone_trait() {
|
||||
|
|
@ -1367,20 +1315,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
if move_span != span || is_loop_message {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::MovedHere {
|
||||
move_span,
|
||||
is_partial,
|
||||
is_move_msg,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(CaptureReasonLabel::MovedHere {
|
||||
move_span,
|
||||
is_partial,
|
||||
is_move_msg,
|
||||
is_loop_message,
|
||||
});
|
||||
}
|
||||
// If the move error occurs due to a loop, don't show
|
||||
// another message for the same span
|
||||
if !is_loop_message {
|
||||
move_spans.var_subdiag(self.dcx(), err, None, |kind, var_span| match kind {
|
||||
move_spans.var_subdiag(err, None, |kind, var_span| match kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -579,15 +579,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None);
|
||||
}
|
||||
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
});
|
||||
} else {
|
||||
binds_to.sort();
|
||||
binds_to.dedup();
|
||||
|
|
@ -620,17 +617,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span: use_span,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span: use_span,
|
||||
});
|
||||
|
||||
use_spans.args_subdiag(self.dcx(), err, |args_span| {
|
||||
use_spans.args_subdiag(err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
|
||||
place: place_desc,
|
||||
args_span,
|
||||
|
|
@ -733,15 +727,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
self.suggest_cloning(err, bind_to.ty, expr, None, None);
|
||||
}
|
||||
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: bind_to.ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: bind_to.ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@ use hir::{ExprKind, Param};
|
|||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{self as hir, BindingMode, ByRef, Node};
|
||||
use rustc_infer::traits;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, Upcast};
|
||||
use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
|
||||
use rustc_middle::{
|
||||
hir::place::PlaceBase,
|
||||
mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
|
||||
|
|
@ -18,6 +17,7 @@ use rustc_span::symbol::{kw, Symbol};
|
|||
use rustc_span::{sym, BytePos, DesugaringKind, Span};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
||||
|
||||
use crate::diagnostics::BorrowedContentSource;
|
||||
|
|
@ -230,7 +230,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
if suggest {
|
||||
borrow_spans.var_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|
||||
|_kind, var_span| {
|
||||
|
|
@ -647,8 +646,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let hir_map = self.infcx.tcx.hir();
|
||||
let def_id = self.body.source.def_id();
|
||||
let Some(local_def_id) = def_id.as_local() else { return };
|
||||
let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) else { return };
|
||||
let body = self.infcx.tcx.hir().body(body_id);
|
||||
let Some(body) = hir_map.maybe_body_owned_by(local_def_id) else { return };
|
||||
|
||||
let mut v = SuggestIndexOperatorAlternativeVisitor {
|
||||
assign_span: span,
|
||||
|
|
@ -656,7 +654,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
ty,
|
||||
suggested: false,
|
||||
};
|
||||
v.visit_body(body);
|
||||
v.visit_body(&body);
|
||||
if !v.suggested {
|
||||
err.help(format!(
|
||||
"to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
|
||||
|
|
@ -746,9 +744,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)`
|
||||
let def_id = self.body.source.def_id();
|
||||
if let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||
&& let body = self.infcx.tcx.hir().body(body_id)
|
||||
&& let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(body).break_value()
|
||||
&& let Some(body) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||
&& let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
|
||||
&& let node = self.infcx.tcx.hir_node(hir_id)
|
||||
&& let hir::Node::LetStmt(hir::LetStmt {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
|
|
@ -867,8 +864,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id())
|
||||
&& let Block(block, _) = hir_map.body(body_id).value.kind
|
||||
if let Some(body) = hir_map.maybe_body_owned_by(self.mir_def_id())
|
||||
&& let Block(block, _) = body.value.kind
|
||||
{
|
||||
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
|
||||
// expression with that span in order to identify potential fixes when encountering a
|
||||
|
|
@ -939,60 +936,85 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let node = self.infcx.tcx.hir_node(fn_call_id);
|
||||
let def_id = hir.enclosing_body_owner(fn_call_id);
|
||||
let mut look_at_return = true;
|
||||
// If we can detect the expression to be an `fn` call where the closure was an argument,
|
||||
// we point at the `fn` definition argument...
|
||||
if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Call(func, args), .. }) = node {
|
||||
let arg_pos = args
|
||||
|
||||
// If the HIR node is a function or method call gets the def ID
|
||||
// of the called function or method and the span and args of the call expr
|
||||
let get_call_details = || {
|
||||
let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let typeck_results = self.infcx.tcx.typeck(def_id);
|
||||
|
||||
match kind {
|
||||
hir::ExprKind::Call(expr, args) => {
|
||||
if let Some(ty::FnDef(def_id, _)) =
|
||||
typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind())
|
||||
{
|
||||
Some((*def_id, expr.span, *args))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
hir::ExprKind::MethodCall(_, _, args, span) => {
|
||||
if let Some(def_id) = typeck_results.type_dependent_def_id(*hir_id) {
|
||||
Some((def_id, *span, *args))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
|
||||
// If we can detect the expression to be an function or method call where the closure was an argument,
|
||||
// we point at the function or method definition argument...
|
||||
if let Some((callee_def_id, call_span, call_args)) = get_call_details() {
|
||||
let arg_pos = call_args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, arg)| arg.hir_id == closure_id)
|
||||
.map(|(pos, _)| pos)
|
||||
.next();
|
||||
let tables = self.infcx.tcx.typeck(def_id);
|
||||
if let Some(ty::FnDef(def_id, _)) =
|
||||
tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind())
|
||||
{
|
||||
let arg = match hir.get_if_local(*def_id) {
|
||||
Some(
|
||||
hir::Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Fn(sig, ..), ..
|
||||
|
||||
let arg = match hir.get_if_local(callee_def_id) {
|
||||
Some(
|
||||
hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(sig, _),
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(sig, _),
|
||||
..
|
||||
}),
|
||||
) => Some(
|
||||
arg_pos
|
||||
.and_then(|pos| {
|
||||
sig.decl.inputs.get(
|
||||
pos + if sig.decl.implicit_self.has_implicit_self() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
},
|
||||
)
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(sig, _),
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(sig, _),
|
||||
..
|
||||
}),
|
||||
) => Some(
|
||||
arg_pos
|
||||
.and_then(|pos| {
|
||||
sig.decl.inputs.get(
|
||||
pos + if sig.decl.implicit_self.has_implicit_self() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|arg| arg.span)
|
||||
.unwrap_or(ident.span),
|
||||
),
|
||||
_ => None,
|
||||
};
|
||||
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(closure_span, "in this closure");
|
||||
look_at_return = false;
|
||||
}
|
||||
.map(|arg| arg.span)
|
||||
.unwrap_or(ident.span),
|
||||
),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(span) = arg {
|
||||
err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
|
||||
err.span_label(call_span, "expects `Fn` instead of `FnMut`");
|
||||
err.span_label(closure_span, "in this closure");
|
||||
look_at_return = false;
|
||||
}
|
||||
}
|
||||
|
||||
if look_at_return && hir.get_return_block(closure_id).is_some() {
|
||||
if look_at_return && hir.get_fn_id_for_return_block(closure_id).is_some() {
|
||||
// ...otherwise we are probably in the tail expression of the function, point at the
|
||||
// return type.
|
||||
match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
|
||||
|
|
@ -1022,7 +1044,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
|
||||
let source = self.body.source;
|
||||
let hir = self.infcx.tcx.hir();
|
||||
if let InstanceDef::Item(def_id) = source.instance
|
||||
if let InstanceKind::Item(def_id) = source.instance
|
||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
||||
&& let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
|
||||
&& let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
|
||||
|
|
@ -1189,10 +1211,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
Some((false, err_label_span, message, _)) => {
|
||||
let def_id = self.body.source.def_id();
|
||||
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||
&& let Some(body) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||
{
|
||||
let body = self.infcx.tcx.hir().body(body_id);
|
||||
BindingFinder { span: err_label_span }.visit_body(body).break_value()
|
||||
BindingFinder { span: err_label_span }.visit_body(&body).break_value()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
|||
|
|
@ -361,6 +361,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
|
||||
let diag = unexpected_hidden_region_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.mir_def_id(),
|
||||
span,
|
||||
named_ty,
|
||||
named_region,
|
||||
|
|
@ -453,7 +454,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// Check if we can use one of the "nice region errors".
|
||||
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
|
||||
let infer_err = self.infcx.err_ctxt();
|
||||
let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f);
|
||||
let nice =
|
||||
NiceRegionError::new_from_span(&infer_err, self.mir_def_id(), cause.span, o, f);
|
||||
if let Some(diag) = nice.try_report_from_nll() {
|
||||
self.buffer_error(diag);
|
||||
return;
|
||||
|
|
@ -629,13 +631,13 @@ 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.subdiagnostic(self.dcx(), VarHereDenote::Defined { span: upvar_def_span });
|
||||
diag.subdiagnostic(self.dcx(), VarHereDenote::Captured { span: upvar_span });
|
||||
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.subdiagnostic(self.dcx(), VarHereDenote::FnMutInferred { span: fr_span });
|
||||
diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
|
||||
}
|
||||
|
||||
self.suggest_move_on_borrowing_closure(&mut diag);
|
||||
|
|
@ -808,7 +810,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
},
|
||||
};
|
||||
|
||||
diag.subdiagnostic(self.dcx(), err_category);
|
||||
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);
|
||||
|
|
@ -843,14 +845,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
if *outlived_f != ty::ReStatic {
|
||||
return;
|
||||
}
|
||||
let suitable_region = self.infcx.tcx.is_suitable_region(f);
|
||||
let suitable_region = self.infcx.tcx.is_suitable_region(self.mir_def_id(), f);
|
||||
let Some(suitable_region) = suitable_region else {
|
||||
return;
|
||||
};
|
||||
|
||||
let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.def_id);
|
||||
|
||||
let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
|
||||
let param = if let Some(param) =
|
||||
find_param_with_region(self.infcx.tcx, self.mir_def_id(), f, outlived_f)
|
||||
{
|
||||
param
|
||||
} else {
|
||||
return;
|
||||
|
|
@ -959,7 +963,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
return;
|
||||
};
|
||||
|
||||
let param = match find_param_with_region(tcx, f, o) {
|
||||
let param = match find_param_with_region(tcx, self.mir_def_id(), f, o) {
|
||||
Some(param) => param,
|
||||
None => return,
|
||||
};
|
||||
|
|
@ -1004,7 +1008,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
ident.span,
|
||||
"calling this method introduces the `impl`'s `'static` requirement",
|
||||
);
|
||||
err.subdiagnostic(self.dcx(), RequireStaticErr::UsedImpl { multi_span });
|
||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"consider relaxing the implicit `'static` requirement",
|
||||
|
|
@ -1022,25 +1026,30 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
return;
|
||||
};
|
||||
|
||||
let Some((ty_sub, _)) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.is_suitable_region(sub)
|
||||
.and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.bound_region))
|
||||
let Some((ty_sub, _)) =
|
||||
self.infcx.tcx.is_suitable_region(self.mir_def_id(), sub).and_then(|anon_reg| {
|
||||
find_anon_type(self.infcx.tcx, self.mir_def_id(), sub, &anon_reg.bound_region)
|
||||
})
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some((ty_sup, _)) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.is_suitable_region(sup)
|
||||
.and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.bound_region))
|
||||
let Some((ty_sup, _)) =
|
||||
self.infcx.tcx.is_suitable_region(self.mir_def_id(), sup).and_then(|anon_reg| {
|
||||
find_anon_type(self.infcx.tcx, self.mir_def_id(), sup, &anon_reg.bound_region)
|
||||
})
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
|
||||
suggest_adding_lifetime_params(
|
||||
self.infcx.tcx,
|
||||
diag,
|
||||
self.mir_def_id(),
|
||||
sub,
|
||||
ty_sup,
|
||||
ty_sub,
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
|
|
@ -1174,8 +1183,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body_id = map.body_owned_by(self.mir_def_id());
|
||||
let expr = &map.body(body_id).value.peel_blocks();
|
||||
let body = map.body_owned_by(self.mir_def_id());
|
||||
let expr = &body.value.peel_blocks();
|
||||
let mut closure_span = None::<rustc_span::Span>;
|
||||
match expr.kind {
|
||||
hir::ExprKind::MethodCall(.., args, _) => {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_middle::ty::print::RegionHighlightMode;
|
|||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use crate::{universal_regions::DefiningTy, MirBorrowckCtxt};
|
||||
|
|
@ -289,7 +289,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
debug!("give_region_a_name: error_region = {:?}", error_region);
|
||||
match *error_region {
|
||||
ty::ReEarlyParam(ebr) => ebr.has_name().then(|| {
|
||||
let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
|
||||
let def_id = tcx.generics_of(self.mir_def_id()).region_param(ebr, tcx).def_id;
|
||||
let span = tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
|
||||
RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyParamRegion(span) }
|
||||
}),
|
||||
|
||||
|
|
@ -627,9 +628,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
| GenericArgKind::Const(_),
|
||||
_,
|
||||
) => {
|
||||
// This was previously a `span_delayed_bug` and could be
|
||||
// reached by the test for #82126, but no longer.
|
||||
self.dcx().span_bug(
|
||||
self.dcx().span_delayed_bug(
|
||||
hir_arg.span(),
|
||||
format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
|
||||
);
|
||||
|
|
@ -842,13 +841,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
}) = opaque_ty.kind
|
||||
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
||||
&& let Some(args) = segment.args
|
||||
&& let [
|
||||
hir::TypeBinding {
|
||||
ident: Ident { name: sym::Output, .. },
|
||||
kind: hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) },
|
||||
..
|
||||
},
|
||||
] = args.bindings
|
||||
&& let [constraint] = args.constraints
|
||||
&& constraint.ident.name == sym::Output
|
||||
&& let Some(ty) = constraint.ty()
|
||||
{
|
||||
ty
|
||||
} else {
|
||||
|
|
@ -912,7 +907,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
};
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let region_parent = tcx.parent(region.def_id);
|
||||
let region_def = tcx.generics_of(self.mir_def_id()).region_param(region, tcx).def_id;
|
||||
let region_parent = tcx.parent(region_def);
|
||||
let DefKind::Impl { .. } = tcx.def_kind(region_parent) else {
|
||||
return None;
|
||||
};
|
||||
|
|
@ -925,7 +921,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
Some(RegionName {
|
||||
name: self.synthesize_region_name(),
|
||||
source: RegionNameSource::AnonRegionFromImplSignature(
|
||||
tcx.def_span(region.def_id),
|
||||
tcx.def_span(region_def),
|
||||
// FIXME(compiler-errors): Does this ever actually show up
|
||||
// anywhere other than the self type? I couldn't create an
|
||||
// example of a `'_` in the impl's trait being referenceable.
|
||||
|
|
|
|||
|
|
@ -15,8 +15,31 @@ use std::path::Path;
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RustcFacts;
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A (kinda) newtype of `RegionVid` so we can implement `Atom` on it.
|
||||
#[orderable]
|
||||
#[debug_format = "'?{}"]
|
||||
pub struct PoloniusRegionVid {}
|
||||
}
|
||||
|
||||
impl polonius_engine::Atom for PoloniusRegionVid {
|
||||
fn index(self) -> usize {
|
||||
self.as_usize()
|
||||
}
|
||||
}
|
||||
impl From<RegionVid> for PoloniusRegionVid {
|
||||
fn from(value: RegionVid) -> Self {
|
||||
Self::from_usize(value.as_usize())
|
||||
}
|
||||
}
|
||||
impl From<PoloniusRegionVid> for RegionVid {
|
||||
fn from(value: PoloniusRegionVid) -> Self {
|
||||
Self::from_usize(value.as_usize())
|
||||
}
|
||||
}
|
||||
|
||||
impl polonius_engine::FactTypes for RustcFacts {
|
||||
type Origin = RegionVid;
|
||||
type Origin = PoloniusRegionVid;
|
||||
type Loan = BorrowIndex;
|
||||
type Point = LocationIndex;
|
||||
type Variable = Local;
|
||||
|
|
@ -119,7 +142,7 @@ trait FactRow {
|
|||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl FactRow for RegionVid {
|
||||
impl FactRow for PoloniusRegionVid {
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! This query borrow-checks the MIR to (further) ensure it is not broken.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
@ -10,8 +10,10 @@
|
|||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(try_blocks)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
|
@ -564,7 +566,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
|
|||
fn_self_span_reported: FxIndexSet<Span>,
|
||||
/// This field keeps track of errors reported in the checking of uninitialized variables,
|
||||
/// so that we don't report seemingly duplicate errors.
|
||||
uninitialized_error_reported: FxIndexSet<PlaceRef<'tcx>>,
|
||||
uninitialized_error_reported: FxIndexSet<Local>,
|
||||
/// This field keeps track of all the local variables that are declared mut and are mutated.
|
||||
/// Used for the warning issued by an unused mutable local variable.
|
||||
used_mut: FxIndexSet<Local>,
|
||||
|
|
@ -1312,8 +1314,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
|
||||
| Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
self.consume_operand(location, (operand1, span), flow_state);
|
||||
self.consume_operand(location, (operand2, span), flow_state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,8 +125,8 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
|||
placeholder_indices,
|
||||
placeholder_index_to_region: _,
|
||||
liveness_constraints,
|
||||
outlives_constraints,
|
||||
member_constraints,
|
||||
mut outlives_constraints,
|
||||
mut member_constraints,
|
||||
universe_causes,
|
||||
type_tests,
|
||||
} = constraints;
|
||||
|
|
@ -144,6 +144,16 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
|||
&universal_region_relations,
|
||||
);
|
||||
|
||||
if let Some(guar) = universal_regions.tainted_by_errors() {
|
||||
// Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all
|
||||
// outlives bounds that we may end up checking.
|
||||
outlives_constraints = Default::default();
|
||||
member_constraints = Default::default();
|
||||
|
||||
// Also taint the entire scope.
|
||||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
let mut regioncx = RegionInferenceContext::new(
|
||||
infcx,
|
||||
var_origins,
|
||||
|
|
|
|||
|
|
@ -302,8 +302,7 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
|
||||
| Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
self.consume_operand(location, operand1);
|
||||
self.consume_operand(location, operand2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::facts::AllFacts;
|
||||
use crate::facts::{AllFacts, PoloniusRegionVid};
|
||||
use crate::location::LocationTable;
|
||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
|
@ -137,7 +137,9 @@ fn emit_universal_region_facts(
|
|||
// the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
|
||||
// added to the existing number of loans, as if they succeeded them in the set.
|
||||
//
|
||||
all_facts.universal_region.extend(universal_regions.universal_regions());
|
||||
all_facts
|
||||
.universal_region
|
||||
.extend(universal_regions.universal_regions().map(PoloniusRegionVid::from));
|
||||
let borrow_count = borrow_set.len();
|
||||
debug!(
|
||||
"emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
|
||||
|
|
@ -148,7 +150,7 @@ fn emit_universal_region_facts(
|
|||
for universal_region in universal_regions.universal_regions() {
|
||||
let universal_region_idx = universal_region.index();
|
||||
let placeholder_loan_idx = borrow_count + universal_region_idx;
|
||||
all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
|
||||
all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
|
||||
}
|
||||
|
||||
// 2: the universal region relations `outlives` constraints are emitted as
|
||||
|
|
@ -160,7 +162,7 @@ fn emit_universal_region_facts(
|
|||
fr1={:?}, fr2={:?}",
|
||||
fr1, fr2
|
||||
);
|
||||
all_facts.known_placeholder_subset.push((fr1, fr2));
|
||||
all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ use std::rc::Rc;
|
|||
use rustc_data_structures::binary_search_util;
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_data_structures::graph::scc::{self, Sccs};
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::outlives::test_type_match;
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||
|
|
@ -19,7 +19,7 @@ use rustc_middle::mir::{
|
|||
};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
@ -46,6 +46,97 @@ mod reverse_sccs;
|
|||
|
||||
pub mod values;
|
||||
|
||||
pub type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex, RegionTracker>;
|
||||
|
||||
/// An annotation for region graph SCCs that tracks
|
||||
/// the values of its elements.
|
||||
#[derive(Copy, Debug, Clone)]
|
||||
pub struct RegionTracker {
|
||||
/// The largest universe of a placeholder reached from this SCC.
|
||||
/// This includes placeholders within this SCC.
|
||||
max_placeholder_universe_reached: UniverseIndex,
|
||||
|
||||
/// The smallest universe index reachable form the nodes of this SCC.
|
||||
min_reachable_universe: UniverseIndex,
|
||||
|
||||
/// The representative Region Variable Id for this SCC. We prefer
|
||||
/// placeholders over existentially quantified variables, otherwise
|
||||
/// it's the one with the smallest Region Variable ID.
|
||||
representative: RegionVid,
|
||||
|
||||
/// Is the current representative a placeholder?
|
||||
representative_is_placeholder: bool,
|
||||
|
||||
/// Is the current representative existentially quantified?
|
||||
representative_is_existential: bool,
|
||||
}
|
||||
|
||||
impl scc::Annotation for RegionTracker {
|
||||
fn merge_scc(mut self, mut other: Self) -> Self {
|
||||
// Prefer any placeholder over any existential
|
||||
if other.representative_is_placeholder && self.representative_is_existential {
|
||||
other.merge_min_max_seen(&self);
|
||||
return other;
|
||||
}
|
||||
|
||||
if self.representative_is_placeholder && other.representative_is_existential
|
||||
|| (self.representative <= other.representative)
|
||||
{
|
||||
self.merge_min_max_seen(&other);
|
||||
return self;
|
||||
}
|
||||
other.merge_min_max_seen(&self);
|
||||
other
|
||||
}
|
||||
|
||||
fn merge_reached(mut self, other: Self) -> Self {
|
||||
// No update to in-component values, only add seen values.
|
||||
self.merge_min_max_seen(&other);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionTracker {
|
||||
fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
|
||||
let (representative_is_placeholder, representative_is_existential) = match definition.origin
|
||||
{
|
||||
rustc_infer::infer::NllRegionVariableOrigin::FreeRegion => (false, false),
|
||||
rustc_infer::infer::NllRegionVariableOrigin::Placeholder(_) => (true, false),
|
||||
rustc_infer::infer::NllRegionVariableOrigin::Existential { .. } => (false, true),
|
||||
};
|
||||
|
||||
let placeholder_universe =
|
||||
if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT };
|
||||
|
||||
Self {
|
||||
max_placeholder_universe_reached: placeholder_universe,
|
||||
min_reachable_universe: definition.universe,
|
||||
representative: rvid,
|
||||
representative_is_placeholder,
|
||||
representative_is_existential,
|
||||
}
|
||||
}
|
||||
fn universe(self) -> UniverseIndex {
|
||||
self.min_reachable_universe
|
||||
}
|
||||
|
||||
fn merge_min_max_seen(&mut self, other: &Self) {
|
||||
self.max_placeholder_universe_reached = std::cmp::max(
|
||||
self.max_placeholder_universe_reached,
|
||||
other.max_placeholder_universe_reached,
|
||||
);
|
||||
|
||||
self.min_reachable_universe =
|
||||
std::cmp::min(self.min_reachable_universe, other.min_reachable_universe);
|
||||
}
|
||||
|
||||
/// Returns `true` if during the annotated SCC reaches a placeholder
|
||||
/// with a universe larger than the smallest reachable one, `false` otherwise.
|
||||
pub fn has_incompatible_universes(&self) -> bool {
|
||||
self.universe().cannot_name(self.max_placeholder_universe_reached)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RegionInferenceContext<'tcx> {
|
||||
pub var_infos: VarInfos,
|
||||
|
||||
|
|
@ -72,7 +163,7 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// The SCC computed from `constraints` and the constraint
|
||||
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
|
||||
/// compute the values of each region.
|
||||
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
|
||||
constraint_sccs: Rc<ConstraintSccs>,
|
||||
|
||||
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
|
||||
/// `B: A`. This is used to compute the universal regions that are required
|
||||
|
|
@ -91,22 +182,6 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// Map universe indexes to information on why we created it.
|
||||
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
|
||||
/// Contains the minimum universe of any variable within the same
|
||||
/// SCC. We will ensure that no SCC contains values that are not
|
||||
/// visible from this index.
|
||||
scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
|
||||
|
||||
/// Contains the "representative" region of each SCC.
|
||||
/// It is defined as the one with the minimal RegionVid, favoring
|
||||
/// free regions, then placeholders, then existential regions.
|
||||
///
|
||||
/// It is a hacky way to manage checking regions for equality,
|
||||
/// since we can 'canonicalize' each region to the representative
|
||||
/// of its SCC and be sure that -- if they have the same repr --
|
||||
/// they *must* be equal (though not having the same repr does not
|
||||
/// mean they are unequal).
|
||||
scc_representatives: IndexVec<ConstraintSccIndex, ty::RegionVid>,
|
||||
|
||||
/// The final inferred values of the region variables; we compute
|
||||
/// one value per SCC. To get the value for any given *region*,
|
||||
/// you first find which scc it is a part of.
|
||||
|
|
@ -151,7 +226,7 @@ pub(crate) struct AppliedMemberConstraint {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct RegionDefinition<'tcx> {
|
||||
pub struct RegionDefinition<'tcx> {
|
||||
/// What kind of variable is this -- a free region? existential
|
||||
/// variable? etc. (See the `NllRegionVariableOrigin` for more
|
||||
/// info.)
|
||||
|
|
@ -250,7 +325,7 @@ pub enum ExtraConstraintInfo {
|
|||
}
|
||||
|
||||
#[instrument(skip(infcx, sccs), level = "debug")]
|
||||
fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>) {
|
||||
fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
||||
let var_to_origin = infcx.reg_var_to_origin.borrow();
|
||||
|
|
@ -264,7 +339,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc<Sccs<RegionVid, Con
|
|||
}
|
||||
debug!("{}", reg_vars_to_origins_str);
|
||||
|
||||
let num_components = sccs.scc_data().ranges().len();
|
||||
let num_components = sccs.num_sccs();
|
||||
let mut components = vec![FxIndexSet::default(); num_components];
|
||||
|
||||
for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
|
||||
|
|
@ -301,10 +376,11 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc<Sccs<RegionVid, Con
|
|||
|
||||
let mut scc_node_to_edges = FxIndexMap::default();
|
||||
for (scc_idx, repr) in components_representatives.iter() {
|
||||
let edges_range = sccs.scc_data().ranges()[*scc_idx].clone();
|
||||
let edges = &sccs.scc_data().all_successors()[edges_range];
|
||||
let edge_representatives =
|
||||
edges.iter().map(|scc_idx| components_representatives[scc_idx]).collect::<Vec<_>>();
|
||||
let edge_representatives = sccs
|
||||
.successors(*scc_idx)
|
||||
.iter()
|
||||
.map(|scc_idx| components_representatives[scc_idx])
|
||||
.collect::<Vec<_>>();
|
||||
scc_node_to_edges.insert((scc_idx, repr), edge_representatives);
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +396,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// The `outlives_constraints` and `type_tests` are an initial set
|
||||
/// of constraints produced by the MIR type check.
|
||||
pub(crate) fn new(
|
||||
_infcx: &BorrowckInferCtxt<'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
var_infos: VarInfos,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
placeholder_indices: Rc<PlaceholderIndices>,
|
||||
|
|
@ -343,13 +419,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
|
||||
let fr_static = universal_regions.fr_static;
|
||||
let constraints = Frozen::freeze(outlives_constraints);
|
||||
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
|
||||
let fr_static = universal_regions.fr_static;
|
||||
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));
|
||||
let constraint_sccs = {
|
||||
let constraint_graph = constraints.graph(definitions.len());
|
||||
let region_graph = &constraint_graph.region_graph(&constraints, fr_static);
|
||||
let sccs = ConstraintSccs::new_with_annotation(®ion_graph, |r| {
|
||||
RegionTracker::new(r, &definitions[r])
|
||||
});
|
||||
Rc::new(sccs)
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
sccs_info(_infcx, constraint_sccs.clone());
|
||||
sccs_info(infcx, &constraint_sccs);
|
||||
}
|
||||
|
||||
let mut scc_values =
|
||||
|
|
@ -360,10 +443,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
scc_values.merge_liveness(scc, region, &liveness_constraints);
|
||||
}
|
||||
|
||||
let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions);
|
||||
|
||||
let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
|
||||
|
||||
let member_constraints =
|
||||
Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
|
||||
|
||||
|
|
@ -378,8 +457,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
member_constraints,
|
||||
member_constraints_applied: Vec::new(),
|
||||
universe_causes,
|
||||
scc_universes,
|
||||
scc_representatives,
|
||||
scc_values,
|
||||
type_tests,
|
||||
universal_regions,
|
||||
|
|
@ -391,123 +468,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Each SCC is the combination of many region variables which
|
||||
/// have been equated. Therefore, we can associate a universe with
|
||||
/// each SCC which is minimum of all the universes of its
|
||||
/// constituent regions -- this is because whatever value the SCC
|
||||
/// takes on must be a value that each of the regions within the
|
||||
/// SCC could have as well. This implies that the SCC must have
|
||||
/// the minimum, or narrowest, universe.
|
||||
fn compute_scc_universes(
|
||||
constraint_sccs: &Sccs<RegionVid, ConstraintSccIndex>,
|
||||
definitions: &IndexSlice<RegionVid, RegionDefinition<'tcx>>,
|
||||
) -> IndexVec<ConstraintSccIndex, ty::UniverseIndex> {
|
||||
let num_sccs = constraint_sccs.num_sccs();
|
||||
let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs);
|
||||
|
||||
debug!("compute_scc_universes()");
|
||||
|
||||
// For each region R in universe U, ensure that the universe for the SCC
|
||||
// that contains R is "no bigger" than U. This effectively sets the universe
|
||||
// for each SCC to be the minimum of the regions within.
|
||||
for (region_vid, region_definition) in definitions.iter_enumerated() {
|
||||
let scc = constraint_sccs.scc(region_vid);
|
||||
let scc_universe = &mut scc_universes[scc];
|
||||
let scc_min = std::cmp::min(region_definition.universe, *scc_universe);
|
||||
if scc_min != *scc_universe {
|
||||
*scc_universe = scc_min;
|
||||
debug!(
|
||||
"compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \
|
||||
because it contains {region_vid:?} in {region_universe:?}",
|
||||
scc = scc,
|
||||
scc_min = scc_min,
|
||||
region_vid = region_vid,
|
||||
region_universe = region_definition.universe,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Walk each SCC `A` and `B` such that `A: B`
|
||||
// and ensure that universe(A) can see universe(B).
|
||||
//
|
||||
// This serves to enforce the 'empty/placeholder' hierarchy
|
||||
// (described in more detail on `RegionKind`):
|
||||
//
|
||||
// ```
|
||||
// static -----+
|
||||
// | |
|
||||
// empty(U0) placeholder(U1)
|
||||
// | /
|
||||
// empty(U1)
|
||||
// ```
|
||||
//
|
||||
// In particular, imagine we have variables R0 in U0 and R1
|
||||
// created in U1, and constraints like this;
|
||||
//
|
||||
// ```
|
||||
// R1: !1 // R1 outlives the placeholder in U1
|
||||
// R1: R0 // R1 outlives R0
|
||||
// ```
|
||||
//
|
||||
// Here, we wish for R1 to be `'static`, because it
|
||||
// cannot outlive `placeholder(U1)` and `empty(U0)` any other way.
|
||||
//
|
||||
// Thanks to this loop, what happens is that the `R1: R0`
|
||||
// constraint lowers the universe of `R1` to `U0`, which in turn
|
||||
// means that the `R1: !1` constraint will (later) cause
|
||||
// `R1` to become `'static`.
|
||||
for scc_a in constraint_sccs.all_sccs() {
|
||||
for &scc_b in constraint_sccs.successors(scc_a) {
|
||||
let scc_universe_a = scc_universes[scc_a];
|
||||
let scc_universe_b = scc_universes[scc_b];
|
||||
let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b);
|
||||
if scc_universe_a != scc_universe_min {
|
||||
scc_universes[scc_a] = scc_universe_min;
|
||||
|
||||
debug!(
|
||||
"compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \
|
||||
because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}",
|
||||
scc_a = scc_a,
|
||||
scc_b = scc_b,
|
||||
scc_universe_min = scc_universe_min,
|
||||
scc_universe_b = scc_universe_b
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("compute_scc_universes: scc_universe = {:#?}", scc_universes);
|
||||
|
||||
scc_universes
|
||||
}
|
||||
|
||||
/// For each SCC, we compute a unique `RegionVid`. See the
|
||||
/// `scc_representatives` field of `RegionInferenceContext` for
|
||||
/// more details.
|
||||
fn compute_scc_representatives(
|
||||
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
|
||||
definitions: &IndexSlice<RegionVid, RegionDefinition<'tcx>>,
|
||||
) -> IndexVec<ConstraintSccIndex, ty::RegionVid> {
|
||||
let num_sccs = constraints_scc.num_sccs();
|
||||
let mut scc_representatives = IndexVec::from_elem_n(RegionVid::MAX, num_sccs);
|
||||
|
||||
// Iterate over all RegionVids *in-order* and pick the least RegionVid as the
|
||||
// representative of its SCC. This naturally prefers free regions over others.
|
||||
for (vid, def) in definitions.iter_enumerated() {
|
||||
let repr = &mut scc_representatives[constraints_scc.scc(vid)];
|
||||
if *repr == ty::RegionVid::MAX {
|
||||
*repr = vid;
|
||||
} else if matches!(def.origin, NllRegionVariableOrigin::Placeholder(_))
|
||||
&& matches!(definitions[*repr].origin, NllRegionVariableOrigin::Existential { .. })
|
||||
{
|
||||
// Pick placeholders over existentials even if they have a greater RegionVid.
|
||||
*repr = vid;
|
||||
}
|
||||
}
|
||||
|
||||
scc_representatives
|
||||
}
|
||||
|
||||
/// Initializes the region variables for each universally
|
||||
/// quantified region (lifetime parameter). The first N variables
|
||||
/// always correspond to the regions appearing in the function
|
||||
|
|
@ -528,12 +488,45 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// and (b) any universally quantified regions that it outlives,
|
||||
/// which in this case is just itself. R1 (`'b`) in contrast also
|
||||
/// outlives `'a` and hence contains R0 and R1.
|
||||
///
|
||||
/// This bit of logic also handles invalid universe relations
|
||||
/// for higher-kinded types.
|
||||
///
|
||||
/// We Walk each SCC `A` and `B` such that `A: B`
|
||||
/// and ensure that universe(A) can see universe(B).
|
||||
///
|
||||
/// This serves to enforce the 'empty/placeholder' hierarchy
|
||||
/// (described in more detail on `RegionKind`):
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// static -----+
|
||||
/// | |
|
||||
/// empty(U0) placeholder(U1)
|
||||
/// | /
|
||||
/// empty(U1)
|
||||
/// ```
|
||||
///
|
||||
/// In particular, imagine we have variables R0 in U0 and R1
|
||||
/// created in U1, and constraints like this;
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// R1: !1 // R1 outlives the placeholder in U1
|
||||
/// R1: R0 // R1 outlives R0
|
||||
/// ```
|
||||
///
|
||||
/// Here, we wish for R1 to be `'static`, because it
|
||||
/// cannot outlive `placeholder(U1)` and `empty(U0)` any other way.
|
||||
///
|
||||
/// Thanks to this loop, what happens is that the `R1: R0`
|
||||
/// constraint has lowered the universe of `R1` to `U0`, which in turn
|
||||
/// means that the `R1: !1` constraint here will cause
|
||||
/// `R1` to become `'static`.
|
||||
fn init_free_and_bound_regions(&mut self) {
|
||||
// Update the names (if any)
|
||||
// This iterator has unstable order but we collect it all into an IndexVec
|
||||
for (external_name, variable) in self.universal_regions.named_universal_regions() {
|
||||
debug!(
|
||||
"init_universal_regions: region {:?} has external name {:?}",
|
||||
"init_free_and_bound_regions: region {:?} has external name {:?}",
|
||||
variable, external_name
|
||||
);
|
||||
self.definitions[variable].external_name = Some(external_name);
|
||||
|
|
@ -559,7 +552,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// its universe `ui` and its extensions. So we
|
||||
// can't just add it into `scc` unless the
|
||||
// universe of the scc can name this region.
|
||||
let scc_universe = self.scc_universes[scc];
|
||||
let scc_universe = self.scc_universe(scc);
|
||||
if scc_universe.can_name(placeholder.universe) {
|
||||
self.scc_values.add_element(scc, placeholder);
|
||||
} else {
|
||||
|
|
@ -640,8 +633,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
/// Returns access to the value of `r` for debugging purposes.
|
||||
pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
|
||||
let scc = self.constraint_sccs.scc(r);
|
||||
self.scc_universes[scc]
|
||||
self.scc_universe(self.constraint_sccs.scc(r))
|
||||
}
|
||||
|
||||
/// Once region solving has completed, this function will return the member constraints that
|
||||
|
|
@ -737,8 +729,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// SCC. For each SCC, we visit its successors and compute
|
||||
// their values, then we union all those values to get our
|
||||
// own.
|
||||
let constraint_sccs = self.constraint_sccs.clone();
|
||||
for scc in constraint_sccs.all_sccs() {
|
||||
for scc in self.constraint_sccs.all_sccs() {
|
||||
self.compute_value_for_scc(scc);
|
||||
}
|
||||
|
||||
|
|
@ -817,20 +808,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// if one exists.
|
||||
for c_r in &mut choice_regions {
|
||||
let scc = self.constraint_sccs.scc(*c_r);
|
||||
*c_r = self.scc_representatives[scc];
|
||||
*c_r = self.scc_representative(scc);
|
||||
}
|
||||
|
||||
// If the member region lives in a higher universe, we currently choose
|
||||
// the most conservative option by leaving it unchanged.
|
||||
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
|
||||
|
||||
if !self.constraint_sccs().annotation(scc).universe().is_root() {
|
||||
return;
|
||||
}
|
||||
debug_assert!(
|
||||
self.scc_values.placeholders_contained_in(scc).next().is_none(),
|
||||
"scc {:?} in a member constraint has placeholder value: {:?}",
|
||||
scc,
|
||||
self.scc_values.region_value_str(scc),
|
||||
);
|
||||
|
||||
// The existing value for `scc` is a lower-bound. This will
|
||||
// consist of some set `{P} + {LB}` of points `{P}` and
|
||||
|
|
@ -900,12 +886,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// in `scc_a`. Used during constraint propagation, and only once
|
||||
/// the value of `scc_b` has been computed.
|
||||
fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
|
||||
let universe_a = self.scc_universes[scc_a];
|
||||
let universe_a = self.constraint_sccs().annotation(scc_a).universe();
|
||||
let universe_b = self.constraint_sccs().annotation(scc_b).universe();
|
||||
|
||||
// Quick check: if scc_b's declared universe is a subset of
|
||||
// scc_a's declared universe (typically, both are ROOT), then
|
||||
// it cannot contain any problematic universe elements.
|
||||
if universe_a.can_name(self.scc_universes[scc_b]) {
|
||||
if universe_a.can_name(universe_b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1033,7 +1020,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
debug!(
|
||||
"lower_bound = {:?} r_scc={:?} universe={:?}",
|
||||
lower_bound, r_scc, self.scc_universes[r_scc]
|
||||
lower_bound,
|
||||
r_scc,
|
||||
self.constraint_sccs.annotation(r_scc).universe()
|
||||
);
|
||||
|
||||
// If the type test requires that `T: 'a` where `'a` is a
|
||||
|
|
@ -1321,7 +1310,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
tcx.fold_regions(value, |r, _db| {
|
||||
let vid = self.to_region_vid(r);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
let repr = self.scc_representatives[scc];
|
||||
let repr = self.scc_representative(scc);
|
||||
ty::Region::new_var(tcx, repr)
|
||||
})
|
||||
}
|
||||
|
|
@ -1506,7 +1495,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
subset_errors.sort();
|
||||
subset_errors.dedup();
|
||||
|
||||
for (longer_fr, shorter_fr) in subset_errors.into_iter() {
|
||||
for &(longer_fr, shorter_fr) in subset_errors.into_iter() {
|
||||
debug!(
|
||||
"check_polonius_subset_errors: subset_error longer_fr={:?},\
|
||||
shorter_fr={:?}",
|
||||
|
|
@ -1514,14 +1503,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
);
|
||||
|
||||
let propagated = self.try_propagate_universal_region_error(
|
||||
*longer_fr,
|
||||
*shorter_fr,
|
||||
longer_fr.into(),
|
||||
shorter_fr.into(),
|
||||
&mut propagated_outlives_requirements,
|
||||
);
|
||||
if propagated == RegionRelationCheckResult::Error {
|
||||
errors_buffer.push(RegionErrorKind::RegionError {
|
||||
longer_fr: *longer_fr,
|
||||
shorter_fr: *shorter_fr,
|
||||
longer_fr: longer_fr.into(),
|
||||
shorter_fr: shorter_fr.into(),
|
||||
fr_origin: NllRegionVariableOrigin::FreeRegion,
|
||||
is_reported: true,
|
||||
});
|
||||
|
|
@ -1547,6 +1536,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The minimum universe of any variable reachable from this
|
||||
/// SCC, inside or outside of it.
|
||||
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
|
||||
self.constraint_sccs().annotation(scc).universe()
|
||||
}
|
||||
/// Checks the final value for the free region `fr` to see if it
|
||||
/// grew too large. In particular, examine what `end(X)` points
|
||||
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
|
||||
|
|
@ -1566,8 +1560,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
// Because this free region must be in the ROOT universe, we
|
||||
// know it cannot contain any bound universes.
|
||||
assert!(self.scc_universes[longer_fr_scc].is_root());
|
||||
debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none());
|
||||
assert!(self.scc_universe(longer_fr_scc).is_root());
|
||||
|
||||
// Only check all of the relations for the main representative of each
|
||||
// SCC, otherwise just check that we outlive said representative. This
|
||||
|
|
@ -1575,7 +1568,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// closures.
|
||||
// Note that the representative will be a universal region if there is
|
||||
// one in this SCC, so we will always check the representative here.
|
||||
let representative = self.scc_representatives[longer_fr_scc];
|
||||
let representative = self.scc_representative(longer_fr_scc);
|
||||
if representative != longer_fr {
|
||||
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
|
||||
longer_fr,
|
||||
|
|
@ -1796,16 +1789,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// `true` if `r1` cannot name that placeholder in its
|
||||
/// value; otherwise, returns `false`.
|
||||
pub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
|
||||
debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
|
||||
|
||||
match self.definitions[r2].origin {
|
||||
NllRegionVariableOrigin::Placeholder(placeholder) => {
|
||||
let universe1 = self.definitions[r1].universe;
|
||||
let r1_universe = self.definitions[r1].universe;
|
||||
debug!(
|
||||
"cannot_name_value_of: universe1={:?} placeholder={:?}",
|
||||
universe1, placeholder
|
||||
"cannot_name_value_of: universe1={r1_universe:?} placeholder={:?}",
|
||||
placeholder
|
||||
);
|
||||
universe1.cannot_name(placeholder.universe)
|
||||
r1_universe.cannot_name(placeholder.universe)
|
||||
}
|
||||
|
||||
NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => {
|
||||
|
|
@ -1835,6 +1826,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
///
|
||||
/// Returns: a series of constraints as well as the region `R`
|
||||
/// that passed the target test.
|
||||
#[instrument(skip(self, target_test), ret)]
|
||||
pub(crate) fn find_constraint_paths_between_regions(
|
||||
&self,
|
||||
from_region: RegionVid,
|
||||
|
|
@ -1932,7 +1924,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
#[instrument(skip(self), level = "trace", ret)]
|
||||
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid {
|
||||
trace!(scc = ?self.constraint_sccs.scc(fr1));
|
||||
trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
|
||||
trace!(universe = ?self.region_universe(fr1));
|
||||
self.find_constraint_paths_between_regions(fr1, |r| {
|
||||
// First look for some `r` such that `fr1: r` and `r` is live at `location`
|
||||
trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r));
|
||||
|
|
@ -2252,8 +2244,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// This can be used to quickly under-approximate the regions which are equal to each other
|
||||
/// and their relative orderings.
|
||||
// This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`.
|
||||
pub fn constraint_sccs(&self) -> &Sccs<RegionVid, ConstraintSccIndex> {
|
||||
self.constraint_sccs.as_ref()
|
||||
pub fn constraint_sccs(&self) -> &ConstraintSccs {
|
||||
&self.constraint_sccs
|
||||
}
|
||||
|
||||
/// Access to the region graph, built from the outlives constraints.
|
||||
|
|
@ -2282,6 +2274,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
let point = self.liveness_constraints.point_from_location(location);
|
||||
self.liveness_constraints.is_loan_live_at(loan_idx, point)
|
||||
}
|
||||
|
||||
/// Returns the representative `RegionVid` for a given SCC.
|
||||
/// See `RegionTracker` for how a region variable ID is chosen.
|
||||
///
|
||||
/// It is a hacky way to manage checking regions for equality,
|
||||
/// since we can 'canonicalize' each region to the representative
|
||||
/// of its SCC and be sure that -- if they have the same repr --
|
||||
/// they *must* be equal (though not having the same repr does not
|
||||
/// mean they are unequal).
|
||||
fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid {
|
||||
self.constraint_sccs.annotation(scc).representative
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionDefinition<'tcx> {
|
||||
|
|
@ -2304,5 +2308,5 @@ pub struct BlameConstraint<'tcx> {
|
|||
pub category: ConstraintCategory<'tcx>,
|
||||
pub from_closure: bool,
|
||||
pub cause: ObligationCause<'tcx>,
|
||||
pub variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
pub variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// Use the SCC representative instead of directly using `region`.
|
||||
// See [rustc-dev-guide chapter] § "Strict lifetime equality".
|
||||
let scc = self.constraint_sccs.scc(region.as_var());
|
||||
let vid = self.scc_representatives[scc];
|
||||
let vid = self.scc_representative(scc);
|
||||
let named = match self.definitions[vid].origin {
|
||||
// Iterate over all universal regions in a consistent order and find the
|
||||
// *first* equal region. This makes sure that equal lifetimes will have
|
||||
|
|
@ -213,7 +213,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
let scc = self.constraint_sccs.scc(vid);
|
||||
|
||||
// Special handling of higher-ranked regions.
|
||||
if !self.scc_universes[scc].is_root() {
|
||||
if !self.scc_universe(scc).is_root() {
|
||||
match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
|
||||
// If the region contains a single placeholder then they're equal.
|
||||
Some((0, placeholder)) => {
|
||||
|
|
@ -340,7 +340,7 @@ fn check_opaque_type_well_formed<'tcx>(
|
|||
.with_next_trait_solver(next_trait_solver)
|
||||
.with_opaque_type_inference(parent_def_id)
|
||||
.build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
|
||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
|
||||
fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
|
||||
let const_ = constant.const_;
|
||||
constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location));
|
||||
debug!("constant: {:#?}", constant);
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ use rustc_middle::traits::query::NoSolution;
|
|||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::solve::deeply_normalize;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
use rustc_trait_selection::traits::ScrubbedTraitError;
|
||||
|
||||
use crate::{
|
||||
constraints::OutlivesConstraint,
|
||||
|
|
@ -136,7 +136,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
|
||||
fn convert(
|
||||
&mut self,
|
||||
predicate: ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
|
||||
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
constraint_category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
debug!("generate: constraints at: {:#?}", self.locations);
|
||||
|
|
@ -276,17 +276,18 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
next_outlives_predicates: &mut Vec<(
|
||||
ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
|
||||
ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
ConstraintCategory<'tcx>,
|
||||
)>,
|
||||
) -> Ty<'tcx> {
|
||||
let result = CustomTypeOp::new(
|
||||
|ocx| {
|
||||
deeply_normalize(
|
||||
ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
|
||||
ocx.deeply_normalize(
|
||||
&ObligationCause::dummy_with_span(self.span),
|
||||
self.param_env,
|
||||
ty,
|
||||
)
|
||||
.map_err(|_| NoSolution)
|
||||
.map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution)
|
||||
},
|
||||
"normalize type outlives obligation",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use std::rc::Rc;
|
|||
use crate::{
|
||||
constraints::OutlivesConstraintSet,
|
||||
facts::{AllFacts, AllFactsExt},
|
||||
location::LocationTable,
|
||||
region_infer::values::LivenessValues,
|
||||
universal_regions::UniversalRegions,
|
||||
};
|
||||
|
|
@ -39,7 +38,6 @@ pub(super) fn generate<'mir, 'tcx>(
|
|||
elements: &Rc<DenseLocationMap>,
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
use_polonius: bool,
|
||||
) {
|
||||
debug!("liveness::generate");
|
||||
|
|
@ -53,11 +51,9 @@ pub(super) fn generate<'mir, 'tcx>(
|
|||
compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
|
||||
let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx());
|
||||
|
||||
let polonius_drop_used = facts_enabled.then(|| {
|
||||
let mut drop_used = Vec::new();
|
||||
polonius::populate_access_facts(typeck, body, location_table, move_data, &mut drop_used);
|
||||
drop_used
|
||||
});
|
||||
if facts_enabled {
|
||||
polonius::populate_access_facts(typeck, body, move_data);
|
||||
};
|
||||
|
||||
trace::trace(
|
||||
typeck,
|
||||
|
|
@ -67,7 +63,6 @@ pub(super) fn generate<'mir, 'tcx>(
|
|||
move_data,
|
||||
relevant_live_locals,
|
||||
boring_locals,
|
||||
polonius_drop_used,
|
||||
);
|
||||
|
||||
// Mark regions that should be live where they appear within rvalues or within a call: like
|
||||
|
|
|
|||
|
|
@ -85,13 +85,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UseFactsExtractor<'a, 'tcx> {
|
|||
pub(super) fn populate_access_facts<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'a, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
move_data: &MoveData<'tcx>,
|
||||
//FIXME: this is not mutated, but expected to be modified as
|
||||
// out param, bug?
|
||||
dropped_at: &mut Vec<(Local, Location)>,
|
||||
) {
|
||||
debug!("populate_access_facts()");
|
||||
let location_table = typeck.borrowck_context.location_table;
|
||||
|
||||
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
|
||||
let mut extractor = UseFactsExtractor {
|
||||
|
|
@ -104,10 +101,6 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
|
|||
};
|
||||
extractor.visit_body(body);
|
||||
|
||||
facts.var_dropped_at.extend(
|
||||
dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))),
|
||||
);
|
||||
|
||||
for (local, local_decl) in body.local_decls.iter_enumerated() {
|
||||
debug!(
|
||||
"add use_of_var_derefs_origin facts - local={:?}, type={:?}",
|
||||
|
|
@ -117,7 +110,7 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
|
|||
let universal_regions = &typeck.borrowck_context.universal_regions;
|
||||
typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
|
||||
let region_vid = universal_regions.to_region_vid(region);
|
||||
facts.use_of_var_derefs_origin.push((local, region_vid));
|
||||
facts.use_of_var_derefs_origin.push((local, region_vid.into()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -136,7 +129,7 @@ pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
|
|||
let universal_regions = &typeck.borrowck_context.universal_regions;
|
||||
typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
|
||||
let region_vid = universal_regions.to_region_vid(drop_live_region);
|
||||
facts.drop_of_var_derefs_origin.push((local, region_vid));
|
||||
facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
|||
use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
||||
use crate::location::RichLocation;
|
||||
use crate::{
|
||||
region_infer::values::{self, LiveLoans},
|
||||
type_check::liveness::local_use_map::LocalUseMap,
|
||||
|
|
@ -46,7 +47,6 @@ pub(super) fn trace<'mir, 'tcx>(
|
|||
move_data: &MoveData<'tcx>,
|
||||
relevant_live_locals: Vec<Local>,
|
||||
boring_locals: Vec<Local>,
|
||||
polonius_drop_used: Option<Vec<(Local, Location)>>,
|
||||
) {
|
||||
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
|
||||
|
||||
|
|
@ -93,9 +93,7 @@ pub(super) fn trace<'mir, 'tcx>(
|
|||
|
||||
let mut results = LivenessResults::new(cx);
|
||||
|
||||
if let Some(drop_used) = polonius_drop_used {
|
||||
results.add_extra_drop_facts(drop_used, relevant_live_locals.iter().copied().collect())
|
||||
}
|
||||
results.add_extra_drop_facts(&relevant_live_locals);
|
||||
|
||||
results.compute_for_all_locals(relevant_live_locals);
|
||||
|
||||
|
|
@ -218,21 +216,38 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
|||
///
|
||||
/// Add facts for all locals with free regions, since regions may outlive
|
||||
/// the function body only at certain nodes in the CFG.
|
||||
fn add_extra_drop_facts(
|
||||
&mut self,
|
||||
drop_used: Vec<(Local, Location)>,
|
||||
relevant_live_locals: FxIndexSet<Local>,
|
||||
) {
|
||||
fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) -> Option<()> {
|
||||
let drop_used = self
|
||||
.cx
|
||||
.typeck
|
||||
.borrowck_context
|
||||
.all_facts
|
||||
.as_ref()
|
||||
.map(|facts| facts.var_dropped_at.clone())?;
|
||||
|
||||
let relevant_live_locals: FxIndexSet<_> = relevant_live_locals.iter().copied().collect();
|
||||
|
||||
let locations = IntervalSet::new(self.cx.elements.num_points());
|
||||
|
||||
for (local, location) in drop_used {
|
||||
for (local, location_index) in drop_used {
|
||||
if !relevant_live_locals.contains(&local) {
|
||||
let local_ty = self.cx.body.local_decls[local].ty;
|
||||
if local_ty.has_free_regions() {
|
||||
let location = match self
|
||||
.cx
|
||||
.typeck
|
||||
.borrowck_context
|
||||
.location_table
|
||||
.to_location(location_index)
|
||||
{
|
||||
RichLocation::Start(l) => l,
|
||||
RichLocation::Mid(l) => l,
|
||||
};
|
||||
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// Clear the value of fields that are "per local variable".
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ use rustc_middle::ty::adjustment::PointerCoercion;
|
|||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
|
||||
OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
|
||||
Dynamic, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType,
|
||||
UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArgsRef, UserArgs};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
|
|
@ -188,15 +189,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output);
|
||||
checker.check_signature_annotation(body);
|
||||
|
||||
liveness::generate(
|
||||
&mut checker,
|
||||
body,
|
||||
elements,
|
||||
flow_inits,
|
||||
move_data,
|
||||
location_table,
|
||||
use_polonius,
|
||||
);
|
||||
liveness::generate(&mut checker, body, elements, flow_inits, move_data, use_polonius);
|
||||
|
||||
translate_outlives_facts(&mut checker);
|
||||
let opaque_type_values = infcx.take_opaque_types();
|
||||
|
|
@ -260,16 +253,14 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
|
|||
|constraint: &OutlivesConstraint<'_>| {
|
||||
if let Some(from_location) = constraint.locations.from_location() {
|
||||
Either::Left(iter::once((
|
||||
constraint.sup,
|
||||
constraint.sub,
|
||||
constraint.sup.into(),
|
||||
constraint.sub.into(),
|
||||
location_table.mid_index(from_location),
|
||||
)))
|
||||
} else {
|
||||
Either::Right(
|
||||
location_table
|
||||
.all_points()
|
||||
.map(move |location| (constraint.sup, constraint.sub, location)),
|
||||
)
|
||||
Either::Right(location_table.all_points().map(move |location| {
|
||||
(constraint.sup.into(), constraint.sub.into(), location)
|
||||
}))
|
||||
}
|
||||
},
|
||||
));
|
||||
|
|
@ -310,10 +301,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
self.sanitize_place(place, location, context);
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
|
||||
debug!(?constant, ?location, "visit_constant");
|
||||
fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
|
||||
debug!(?constant, ?location, "visit_const_operand");
|
||||
|
||||
self.super_constant(constant, location);
|
||||
self.super_const_operand(constant, location);
|
||||
let ty = self.sanitize_type(constant, constant.const_.ty());
|
||||
|
||||
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
|
||||
|
|
@ -337,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
if let Some(annotation_index) = constant.user_ty {
|
||||
if let Err(terr) = self.cx.relate_type_and_user_type(
|
||||
constant.const_.ty(),
|
||||
ty::Variance::Invariant,
|
||||
ty::Invariant,
|
||||
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
||||
locations,
|
||||
ConstraintCategory::Boring,
|
||||
|
|
@ -355,7 +346,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
} else {
|
||||
let tcx = self.tcx();
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Ty(ct) => match ct.kind() {
|
||||
Const::Ty(_, ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(_) => {
|
||||
bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
|
||||
}
|
||||
|
|
@ -460,7 +451,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
if let Err(terr) = self.cx.relate_type_and_user_type(
|
||||
ty,
|
||||
ty::Variance::Invariant,
|
||||
ty::Invariant,
|
||||
user_ty,
|
||||
Locations::All(*span),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
|
|
@ -1104,7 +1095,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
) -> Result<(), NoSolution> {
|
||||
// Use this order of parameters because the sup type is usually the
|
||||
// "expected" type in diagnostics.
|
||||
self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
|
||||
self.relate_types(sup, ty::Contravariant, sub, locations, category)
|
||||
}
|
||||
|
||||
#[instrument(skip(self, category), level = "debug")]
|
||||
|
|
@ -1115,7 +1106,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
locations: Locations,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
|
||||
self.relate_types(expected, ty::Invariant, found, locations, category)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
|
@ -1155,7 +1146,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
trace!(?curr_projected_ty);
|
||||
|
||||
let ty = curr_projected_ty.ty;
|
||||
self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
|
||||
self.relate_types(ty, v.xform(ty::Contravariant), a, locations, category)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1257,7 +1248,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if let Some(annotation_index) = self.rvalue_user_ty(rv) {
|
||||
if let Err(terr) = self.relate_type_and_user_type(
|
||||
rv_ty,
|
||||
ty::Variance::Invariant,
|
||||
ty::Invariant,
|
||||
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
|
|
@ -1865,7 +1856,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
if let Operand::Constant(constant) = op {
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Val(..) | Const::Ty(_) => None,
|
||||
Const::Val(..) | Const::Ty(_, _) => None,
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
};
|
||||
|
||||
|
|
@ -2417,8 +2408,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.check_operand(op, location);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_, box (left, right))
|
||||
| Rvalue::CheckedBinaryOp(_, box (left, right)) => {
|
||||
Rvalue::BinaryOp(_, box (left, right)) => {
|
||||
self.check_operand(left, location);
|
||||
self.check_operand(right, location);
|
||||
}
|
||||
|
|
@ -2445,7 +2435,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| Rvalue::Cast(..)
|
||||
| Rvalue::ShallowInitBox(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
| Rvalue::NullaryOp(..)
|
||||
| Rvalue::CopyForDeref(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
|
|
@ -2547,7 +2536,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
|
||||
let region_vid = borrow_region.as_var();
|
||||
all_facts.loan_issued_at.push((
|
||||
region_vid,
|
||||
region_vid.into(),
|
||||
borrow_index,
|
||||
location_table.mid_index(location),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
|
||||
use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases};
|
||||
use rustc_infer::traits::{Obligation, PredicateObligations};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
|
@ -49,14 +50,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
locations: Locations,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
NllTypeRelating::new(
|
||||
self,
|
||||
locations,
|
||||
category,
|
||||
UniverseInfo::other(),
|
||||
ty::Variance::Invariant,
|
||||
)
|
||||
.relate(a, b)?;
|
||||
NllTypeRelating::new(self, locations, category, UniverseInfo::other(), ty::Invariant)
|
||||
.relate(a, b)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +77,7 @@ pub struct NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
/// - Bivariant means that it doesn't matter.
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
ambient_variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
||||
|
|
@ -105,15 +100,15 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
|
||||
fn ambient_covariance(&self) -> bool {
|
||||
match self.ambient_variance {
|
||||
ty::Variance::Covariant | ty::Variance::Invariant => true,
|
||||
ty::Variance::Contravariant | ty::Variance::Bivariant => false,
|
||||
ty::Covariant | ty::Invariant => true,
|
||||
ty::Contravariant | ty::Bivariant => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn ambient_contravariance(&self) -> bool {
|
||||
match self.ambient_variance {
|
||||
ty::Variance::Contravariant | ty::Variance::Invariant => true,
|
||||
ty::Variance::Covariant | ty::Variance::Bivariant => false,
|
||||
ty::Contravariant | ty::Invariant => true,
|
||||
ty::Covariant | ty::Bivariant => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,9 +148,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
"expected at least one opaque type in `relate_opaques`, got {a} and {b}."
|
||||
),
|
||||
};
|
||||
let cause = ObligationCause::dummy_with_span(self.span());
|
||||
let obligations = infcx.handle_opaque_type(a, b, &cause, self.param_env())?.obligations;
|
||||
self.register_obligations(obligations);
|
||||
self.register_goals(infcx.handle_opaque_type(a, b, self.span(), self.param_env())?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +186,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar, _ty| {
|
||||
consts: &mut |_bound_var: ty::BoundVar| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -231,7 +224,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar, _ty| {
|
||||
consts: &mut |_bound_var: ty::BoundVar| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -296,7 +289,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
&mut self,
|
||||
sup: ty::Region<'tcx>,
|
||||
sub: ty::Region<'tcx>,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
) {
|
||||
let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup);
|
||||
|
|
@ -314,7 +307,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.type_checker.infcx.tcx
|
||||
}
|
||||
|
|
@ -324,10 +317,10 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(skip(self, info), level = "trace", ret)]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
@ -337,11 +330,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
|
||||
debug!(?self.ambient_variance);
|
||||
// In a bivariant context this always succeeds.
|
||||
let r = if self.ambient_variance == ty::Variance::Bivariant {
|
||||
Ok(a)
|
||||
} else {
|
||||
self.relate(a, b)
|
||||
};
|
||||
let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
|
||||
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
|
||||
|
|
@ -445,7 +434,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
// We want that
|
||||
//
|
||||
|
|
@ -475,7 +464,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
}
|
||||
|
||||
match self.ambient_variance {
|
||||
ty::Variance::Covariant => {
|
||||
ty::Covariant => {
|
||||
// Covariance, so we want `for<..> A <: for<..> B` --
|
||||
// therefore we compare any instantiation of A (i.e., A
|
||||
// instantiated with existentials) against every
|
||||
|
|
@ -490,7 +479,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
})?;
|
||||
}
|
||||
|
||||
ty::Variance::Contravariant => {
|
||||
ty::Contravariant => {
|
||||
// Contravariance, so we want `for<..> A :> for<..> B` --
|
||||
// therefore we compare every instantiation of A (i.e., A
|
||||
// instantiated with universals) against any
|
||||
|
|
@ -505,7 +494,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
})?;
|
||||
}
|
||||
|
||||
ty::Variance::Invariant => {
|
||||
ty::Invariant => {
|
||||
// Invariant, so we want `for<..> A == for<..> B` --
|
||||
// therefore we want `exists<..> A == for<..> B` and
|
||||
// `exists<..> B == for<..> A`.
|
||||
|
|
@ -526,14 +515,14 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
|||
})?;
|
||||
}
|
||||
|
||||
ty::Variance::Bivariant => {}
|
||||
ty::Bivariant => {}
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.locations.span(self.type_checker.body)
|
||||
}
|
||||
|
|
@ -550,22 +539,32 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx
|
|||
&mut self,
|
||||
obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
|
||||
) {
|
||||
self.register_obligations(
|
||||
obligations
|
||||
.into_iter()
|
||||
.map(|to_pred| {
|
||||
Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred)
|
||||
})
|
||||
.collect(),
|
||||
let tcx = self.tcx();
|
||||
let param_env = self.param_env();
|
||||
self.register_goals(
|
||||
obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)),
|
||||
);
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
fn register_goals(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) {
|
||||
let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
|
||||
self.locations,
|
||||
self.category,
|
||||
InstantiateOpaqueType {
|
||||
obligations,
|
||||
obligations: obligations
|
||||
.into_iter()
|
||||
.map(|goal| {
|
||||
Obligation::new(
|
||||
self.tcx(),
|
||||
ObligationCause::dummy_with_span(self.span()),
|
||||
goal.param_env,
|
||||
goal.predicate,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
// These fields are filled in during execution of the operation
|
||||
base_universe: None,
|
||||
region_constraints: None,
|
||||
|
|
@ -573,25 +572,25 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx
|
|||
);
|
||||
}
|
||||
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
||||
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
|
||||
ty::Covariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
// a :> b is b <: a
|
||||
ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
|
||||
ty::Contravariant => ty::PredicateKind::AliasRelate(
|
||||
b.into(),
|
||||
a.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
|
||||
ty::Invariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
ty::Variance::Bivariant => {
|
||||
ty::Bivariant => {
|
||||
unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)")
|
||||
}
|
||||
})]);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, T
|
|||
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::{ErrorGuaranteed, Symbol};
|
||||
use std::cell::Cell;
|
||||
use std::iter;
|
||||
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
|
@ -186,6 +187,10 @@ struct UniversalRegionIndices<'tcx> {
|
|||
|
||||
/// The vid assigned to `'static`. Used only for diagnostics.
|
||||
pub fr_static: RegionVid,
|
||||
|
||||
/// Whether we've encountered an error region. If we have, cancel all
|
||||
/// outlives errors, as they are likely bogus.
|
||||
pub tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
|
@ -408,6 +413,10 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.indices.tainted_by_errors.get()
|
||||
}
|
||||
}
|
||||
|
||||
struct UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
|
|
@ -663,7 +672,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
|
||||
let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var()));
|
||||
|
||||
UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static }
|
||||
UniversalRegionIndices {
|
||||
indices: global_mapping.chain(arg_mapping).collect(),
|
||||
fr_static,
|
||||
tainted_by_errors: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_inputs_and_output(
|
||||
|
|
@ -868,7 +881,8 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
|||
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
|
||||
if let ty::ReVar(..) = *r {
|
||||
r.as_var()
|
||||
} else if r.is_error() {
|
||||
} else if let ty::ReError(guar) = *r {
|
||||
self.tainted_by_errors.set(Some(guar));
|
||||
// We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the
|
||||
// `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if
|
||||
// errors are being emitted and 2) it leaves the happy path unaffected.
|
||||
|
|
|
|||
|
|
@ -110,6 +110,9 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
|
|||
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
|
||||
.suggestion = remove the value
|
||||
|
||||
builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)`
|
||||
.suggestion = remove the `unsafe(...)`
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
|
||||
.custom = use `std::env::var({$var_expr})` to read the variable at run time
|
||||
|
|
@ -247,5 +250,3 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
|
|||
.label = not a trait
|
||||
.str_lit = try using `#[derive({$sym})]`
|
||||
.other = for example, write `#[derive(Debug)]` for `Debug`
|
||||
|
||||
builtin_macros_unnameable_test_items = cannot test inner items
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::errors;
|
||||
use crate::util::expr_to_spanned_string;
|
||||
use ast::token::IdentIsRaw;
|
||||
use lint::BuiltinLintDiag;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
|
|
@ -45,7 +46,7 @@ pub fn parse_asm_args<'a>(
|
|||
sp: Span,
|
||||
is_global_asm: bool,
|
||||
) -> PResult<'a, AsmArgs> {
|
||||
let dcx = &p.psess.dcx;
|
||||
let dcx = p.dcx();
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp }));
|
||||
|
|
@ -306,7 +307,7 @@ pub fn parse_asm_args<'a>(
|
|||
fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
|
||||
// Tool-only output
|
||||
let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
|
||||
p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
|
||||
p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
|
||||
}
|
||||
|
||||
/// Try to set the provided option in the provided `AsmArgs`.
|
||||
|
|
@ -378,7 +379,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
|
|||
p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
|
||||
|
||||
if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
|
||||
return Err(p.psess.dcx.create_err(errors::NonABI { span: p.token.span }));
|
||||
return Err(p.dcx().create_err(errors::NonABI { span: p.token.span }));
|
||||
}
|
||||
|
||||
let mut new_abis = Vec::new();
|
||||
|
|
@ -389,7 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
|
|||
}
|
||||
Err(opt_lit) => {
|
||||
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
|
||||
let mut err = p.psess.dcx.struct_span_err(span, "expected string literal");
|
||||
let mut err = p.dcx().struct_span_err(span, "expected string literal");
|
||||
err.span_label(span, "not a string literal");
|
||||
return Err(err);
|
||||
}
|
||||
|
|
@ -513,7 +514,7 @@ fn expand_preparsed_asm(
|
|||
lint::builtin::BAD_ASM_STYLE,
|
||||
find_span(".intel_syntax"),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
"avoid using `.intel_syntax`, Intel syntax is the default",
|
||||
BuiltinLintDiag::AvoidUsingIntelSyntax,
|
||||
);
|
||||
}
|
||||
if template_str.contains(".att_syntax") {
|
||||
|
|
@ -521,7 +522,7 @@ fn expand_preparsed_asm(
|
|||
lint::builtin::BAD_ASM_STYLE,
|
||||
find_span(".att_syntax"),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
"avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
|
||||
BuiltinLintDiag::AvoidUsingAttSyntax,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
/// Builds the whole `assert!` expression. For example, `let elem = 1; assert!(elem == 1);` expands to:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(generic_assert_internals)]
|
||||
/// let elem = 1;
|
||||
/// {
|
||||
/// #[allow(unused_imports)]
|
||||
|
|
@ -153,7 +152,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
|
||||
let escaped_expr_str = escape_to_fmt(expr_str);
|
||||
let initial = [
|
||||
TokenTree::token_joint_hidden(
|
||||
TokenTree::token_joint(
|
||||
token::Literal(token::Lit {
|
||||
kind: token::LitKind::Str,
|
||||
symbol: Symbol::intern(&if self.fmt_string.is_empty() {
|
||||
|
|
@ -172,7 +171,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
];
|
||||
let captures = self.capture_decls.iter().flat_map(|cap| {
|
||||
[
|
||||
TokenTree::token_joint_hidden(
|
||||
TokenTree::token_joint(
|
||||
token::Ident(cap.ident.name, IdentIsRaw::No),
|
||||
cap.ident.span,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ impl CfgEval<'_, '_> {
|
|||
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
||||
// 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.psess, orig_tokens, None);
|
||||
let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None);
|
||||
parser.capture_cfg = true;
|
||||
match parse_annotatable_with(&mut parser) {
|
||||
Ok(a) => annotatable = a,
|
||||
|
|
|
|||
|
|
@ -4,19 +4,20 @@ use crate::errors;
|
|||
use rustc_ast::attr::mk_attr;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::{self as ast, AttrItem, AttrStyle};
|
||||
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
||||
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
||||
for raw_attr in attrs {
|
||||
let mut parser = rustc_parse::new_parser_from_source_str(
|
||||
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
raw_attr.clone(),
|
||||
);
|
||||
));
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
|
||||
let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) {
|
||||
Ok(ai) => ai,
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
|
|
@ -25,13 +26,14 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
|||
};
|
||||
let end_span = parser.token.span;
|
||||
if parser.token != token::Eof {
|
||||
psess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
|
||||
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
|
||||
continue;
|
||||
}
|
||||
|
||||
krate.attrs.push(mk_attr(
|
||||
&psess.attr_id_generator,
|
||||
AttrStyle::Inner,
|
||||
unsafety,
|
||||
path,
|
||||
args,
|
||||
start_span.to(end_span),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval;
|
|||
use crate::errors;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind};
|
||||
use rustc_expand::base::{
|
||||
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
|
||||
};
|
||||
|
|
@ -60,6 +60,7 @@ impl MultiItemModifier for Expander {
|
|||
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
|
||||
// paths.
|
||||
report_path_args(sess, meta);
|
||||
report_unsafe_args(sess, meta);
|
||||
meta.path.clone()
|
||||
})
|
||||
.map(|path| DeriveResolution {
|
||||
|
|
@ -159,3 +160,13 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) {
|
||||
match meta.unsafety {
|
||||
Safety::Unsafe(span) => {
|
||||
sess.dcx().emit_err(errors::DeriveUnsafePath { span });
|
||||
}
|
||||
Safety::Default => {}
|
||||
Safety::Safe(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::deriving::generic::*;
|
|||
use crate::errors;
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::walk_list;
|
||||
use rustc_ast::visit::visit_opt;
|
||||
use rustc_ast::{attr, EnumDef, VariantData};
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
@ -224,7 +224,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
|
|||
self.visit_ident(v.ident);
|
||||
self.visit_vis(&v.vis);
|
||||
self.visit_variant_data(&v.data);
|
||||
walk_list!(self, visit_anon_const, &v.disr_expr);
|
||||
visit_opt!(self, visit_anon_const, &v.disr_expr);
|
||||
for attr in &v.attrs {
|
||||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,6 +412,15 @@ fn find_type_parameters(
|
|||
|
||||
impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
|
||||
fn visit_ty(&mut self, ty: &'a ast::Ty) {
|
||||
let stack_len = self.bound_generic_params_stack.len();
|
||||
if let ast::TyKind::BareFn(bare_fn) = &ty.kind
|
||||
&& !bare_fn.generic_params.is_empty()
|
||||
{
|
||||
// Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so
|
||||
// that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622
|
||||
self.bound_generic_params_stack.extend(bare_fn.generic_params.iter().cloned());
|
||||
}
|
||||
|
||||
if let ast::TyKind::Path(_, path) = &ty.kind
|
||||
&& let Some(segment) = path.segments.first()
|
||||
&& self.ty_param_names.contains(&segment.ident.name)
|
||||
|
|
@ -422,7 +431,8 @@ fn find_type_parameters(
|
|||
});
|
||||
}
|
||||
|
||||
visit::walk_ty(self, ty)
|
||||
visit::walk_ty(self, ty);
|
||||
self.bound_generic_params_stack.truncate(stack_len);
|
||||
}
|
||||
|
||||
// Place bound generic params on a stack, to extract them when a type is encountered.
|
||||
|
|
@ -1621,14 +1631,13 @@ impl<'a> TraitDef<'a> {
|
|||
};
|
||||
|
||||
if let Some(ty) = exception {
|
||||
cx.sess.psess.buffer_lint_with_diagnostic(
|
||||
cx.sess.psess.buffer_lint(
|
||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||
sp,
|
||||
ast::CRATE_NODE_ID,
|
||||
format!(
|
||||
"{ty} slice in a packed struct that derives a built-in trait"
|
||||
),
|
||||
rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive,
|
||||
rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive {
|
||||
ty: ty.to_string(),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Wrap the expression in `{...}`, causing a copy.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_errors::{
|
||||
codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan,
|
||||
codes::*, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan,
|
||||
SingleLabelManySpans, SubdiagMessageOp, Subdiagnostic,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
|
|
@ -295,6 +295,13 @@ pub(crate) struct DerivePathArgsValue {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_unsafe_path)]
|
||||
pub(crate) struct DeriveUnsafePath {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_no_default_variant)]
|
||||
#[help]
|
||||
|
|
@ -427,7 +434,7 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
|
|||
// Hand-written implementation to support custom user messages.
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage {
|
||||
#[track_caller]
|
||||
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
#[expect(
|
||||
rustc::untranslatable_diagnostic,
|
||||
reason = "cannot translate user-provided messages"
|
||||
|
|
@ -794,7 +801,7 @@ pub(crate) struct AsmClobberNoReg {
|
|||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg {
|
||||
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
// eager translation as `span_labels` takes `AsRef<str>`
|
||||
let lbl1 = dcx.eagerly_translate_to_string(
|
||||
crate::fluent_generated::builtin_macros_asm_clobber_abi,
|
||||
|
|
|
|||
|
|
@ -556,7 +556,6 @@ fn make_format_args(
|
|||
let arg_name = args.explicit_args()[index].kind.ident().unwrap();
|
||||
ecx.buffered_early_lint.push(BufferedEarlyLint {
|
||||
span: arg_name.span.into(),
|
||||
msg: format!("named argument `{}` is not used by name", arg_name.name).into(),
|
||||
node_id: rustc_ast::CRATE_NODE_ID,
|
||||
lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
|
||||
diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
//! This crate contains implementations of built-in macros and other code generating facilities
|
||||
//! injecting code into the crate before it is lowered to HIR.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
|
|
@ -15,7 +15,9 @@
|
|||
#![feature(lint_reasons)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(try_blocks)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rustc_ast::ptr::P;
|
|||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{self as ast, attr, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
|
||||
use rustc_expand::expand::{AstFragment, ExpansionConfig};
|
||||
use rustc_feature::Features;
|
||||
|
|
@ -38,7 +39,7 @@ enum ProcMacro {
|
|||
struct CollectProcMacros<'a> {
|
||||
macros: Vec<ProcMacro>,
|
||||
in_root: bool,
|
||||
dcx: &'a rustc_errors::DiagCtxt,
|
||||
dcx: DiagCtxtHandle<'a>,
|
||||
source_map: &'a SourceMap,
|
||||
is_proc_macro_crate: bool,
|
||||
is_test_crate: bool,
|
||||
|
|
@ -52,7 +53,7 @@ pub fn inject(
|
|||
is_proc_macro_crate: bool,
|
||||
has_proc_macro_decls: bool,
|
||||
is_test_crate: bool,
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
) {
|
||||
let ecfg = ExpansionConfig::default("proc_macro".to_string(), features);
|
||||
let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ use rustc_expand::base::{
|
|||
resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult,
|
||||
};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_parse::new_parser_from_file;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
|
@ -125,7 +126,7 @@ pub(crate) fn expand_include<'cx>(
|
|||
return ExpandResult::Ready(DummyResult::any(sp, guar));
|
||||
}
|
||||
};
|
||||
let p = new_parser_from_file(cx.psess(), &file, Some(sp));
|
||||
let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp)));
|
||||
|
||||
// If in the included file we have e.g., `mod bar;`,
|
||||
// then the path of `bar.rs` should be relative to the directory of `file`.
|
||||
|
|
@ -147,7 +148,7 @@ pub(crate) fn expand_include<'cx>(
|
|||
INCOMPLETE_INCLUDE,
|
||||
self.p.token.span,
|
||||
self.node_id,
|
||||
"include macro expected single expression in source",
|
||||
BuiltinLintDiag::IncompleteInclude,
|
||||
);
|
||||
}
|
||||
Some(expr)
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ use rustc_ast::mut_visit::*;
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{walk_item, Visitor};
|
||||
use rustc_ast::{attr, ModKind};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_expand::base::{ExtCtxt, ResolverExpand};
|
||||
use rustc_expand::expand::{AstFragment, ExpansionConfig};
|
||||
use rustc_feature::Features;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
|
||||
|
|
@ -163,7 +165,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> {
|
|||
UNNAMEABLE_TEST_ITEMS,
|
||||
attr.span,
|
||||
i.id,
|
||||
crate::fluent_generated::builtin_macros_unnameable_test_items,
|
||||
BuiltinLintDiag::UnnameableTestItems,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -202,6 +204,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
|
|||
let allow_dead_code = attr::mk_attr_nested_word(
|
||||
&self.sess.psess.attr_id_generator,
|
||||
ast::AttrStyle::Outer,
|
||||
ast::Safety::Default,
|
||||
sym::allow,
|
||||
sym::dead_code,
|
||||
self.def_site,
|
||||
|
|
@ -389,7 +392,7 @@ fn get_test_name(i: &ast::Item) -> Option<Symbol> {
|
|||
attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
|
||||
}
|
||||
|
||||
fn get_test_runner(dcx: &rustc_errors::DiagCtxt, krate: &ast::Crate) -> Option<ast::Path> {
|
||||
fn get_test_runner(dcx: DiagCtxtHandle<'_>, krate: &ast::Crate) -> Option<ast::Path> {
|
||||
let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
|
||||
let meta_list = test_attr.meta_item_list()?;
|
||||
let span = test_attr.span;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
|||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
|
||||
use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag};
|
||||
use rustc_parse::{parser, validate_attr};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
|
|
@ -46,7 +46,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable,
|
|||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
attr.span,
|
||||
ecx.current_expansion.lint_node_id,
|
||||
"duplicated attribute",
|
||||
BuiltinLintDiag::DuplicateMacroAttribute,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,20 +2,23 @@
|
|||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait T {
|
||||
type Item;
|
||||
}
|
||||
mod helper {
|
||||
pub trait T {
|
||||
type Item;
|
||||
}
|
||||
|
||||
type Alias<'a> = impl T<Item = &'a ()>;
|
||||
pub type Alias<'a> = impl T<Item = &'a ()>;
|
||||
|
||||
struct S;
|
||||
impl<'a> T for &'a S {
|
||||
type Item = &'a ();
|
||||
}
|
||||
struct S;
|
||||
impl<'a> T for &'a S {
|
||||
type Item = &'a ();
|
||||
}
|
||||
|
||||
fn filter_positive<'a>() -> Alias<'a> {
|
||||
&S
|
||||
pub fn filter_positive<'a>() -> Alias<'a> {
|
||||
&S
|
||||
}
|
||||
}
|
||||
use helper::*;
|
||||
|
||||
fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
fun(filter_positive());
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/wind
|
|||
index ad8e01bfa9b..9ca8e4c16ce 100644
|
||||
--- a/library/std/src/sys/pal/windows/c.rs
|
||||
+++ b/library/std/src/sys/pal/windows/c.rs
|
||||
@@ -323,7 +323,7 @@ pub unsafe fn NtWriteFile(
|
||||
@@ -312,7 +312,7 @@ pub unsafe fn NtWriteFile(
|
||||
|
||||
// Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
|
||||
cfg_if::cfg_if! {
|
||||
|
|
@ -26,8 +26,8 @@ index e427546222a..f2fe42a4d51 100644
|
|||
--- a/library/std/src/sys/pal/windows/rand.rs
|
||||
+++ b/library/std/src/sys/pal/windows/rand.rs
|
||||
@@ -2,7 +2,7 @@
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
|
||||
use crate::sys::c;
|
||||
|
||||
-#[cfg(not(target_vendor = "win7"))]
|
||||
+#[cfg(any())]
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
}
|
||||
|
||||
match instance.def {
|
||||
InstanceDef::Intrinsic(_) => {
|
||||
InstanceKind::Intrinsic(_) => {
|
||||
match crate::intrinsics::codegen_intrinsic_call(
|
||||
fx,
|
||||
instance,
|
||||
|
|
@ -412,7 +412,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
Err(instance) => Some(instance),
|
||||
}
|
||||
}
|
||||
InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => {
|
||||
InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => {
|
||||
// empty drop glue - a nop.
|
||||
let dest = target.expect("Non terminating drop_in_place_real???");
|
||||
let ret_block = fx.get_block(dest);
|
||||
|
|
@ -494,7 +494,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
|
||||
let (func_ref, first_arg_override) = match instance {
|
||||
// Trait object call
|
||||
Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => {
|
||||
Some(Instance { def: InstanceKind::Virtual(_, idx), .. }) => {
|
||||
if fx.clif_comments.enabled() {
|
||||
let nop_inst = fx.bcx.ins().nop();
|
||||
fx.add_comment(
|
||||
|
|
@ -593,11 +593,12 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
source_info: mir::SourceInfo,
|
||||
drop_place: CPlace<'tcx>,
|
||||
target: BasicBlock,
|
||||
) {
|
||||
let ty = drop_place.layout().ty;
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
|
||||
|
||||
if let ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) =
|
||||
if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) =
|
||||
drop_instance.def
|
||||
{
|
||||
// we don't actually need to drop anything
|
||||
|
|
@ -620,10 +621,16 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
let ptr = ptr.get_addr(fx);
|
||||
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
|
||||
|
||||
let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0);
|
||||
let target_block = fx.get_block(target);
|
||||
let continued = fx.bcx.create_block();
|
||||
fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]);
|
||||
fx.bcx.switch_to_block(continued);
|
||||
|
||||
// FIXME(eddyb) perhaps move some of this logic into
|
||||
// `Instance::resolve_drop_in_place`?
|
||||
let virtual_drop = Instance {
|
||||
def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
|
||||
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
||||
args: drop_instance.args,
|
||||
};
|
||||
let fn_abi =
|
||||
|
|
@ -659,8 +666,14 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx);
|
||||
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
|
||||
|
||||
let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0);
|
||||
let target_block = fx.get_block(target);
|
||||
let continued = fx.bcx.create_block();
|
||||
fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]);
|
||||
fx.bcx.switch_to_block(continued);
|
||||
|
||||
let virtual_drop = Instance {
|
||||
def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
|
||||
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
||||
args: drop_instance.args,
|
||||
};
|
||||
let fn_abi =
|
||||
|
|
@ -671,7 +684,7 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
fx.bcx.ins().call_indirect(sig, drop_fn, &[data]);
|
||||
}
|
||||
_ => {
|
||||
assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
|
||||
assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _)));
|
||||
|
||||
let fn_abi =
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
|
||||
|
|
@ -697,4 +710,7 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let target_block = fx.get_block(target);
|
||||
fx.bcx.ins().jump(target_block, &[]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -548,10 +548,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
}
|
||||
TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
|
||||
let drop_place = codegen_place(fx, *place);
|
||||
crate::abi::codegen_drop(fx, source_info, drop_place);
|
||||
|
||||
let target_block = fx.get_block(*target);
|
||||
fx.bcx.ins().jump(target_block, &[]);
|
||||
crate::abi::codegen_drop(fx, source_info, drop_place, *target);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -609,35 +606,44 @@ fn codegen_stmt<'tcx>(
|
|||
let lhs = codegen_operand(fx, &lhs_rhs.0);
|
||||
let rhs = codegen_operand(fx, &lhs_rhs.1);
|
||||
|
||||
let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
|
||||
lval.write_cvalue(fx, res);
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => {
|
||||
let lhs = codegen_operand(fx, &lhs_rhs.0);
|
||||
let rhs = codegen_operand(fx, &lhs_rhs.1);
|
||||
|
||||
let res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
|
||||
let res = if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
|
||||
crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
|
||||
} else {
|
||||
crate::num::codegen_binop(fx, bin_op, lhs, rhs)
|
||||
};
|
||||
lval.write_cvalue(fx, res);
|
||||
}
|
||||
Rvalue::UnaryOp(un_op, ref operand) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
let layout = operand.layout();
|
||||
let val = operand.load_scalar(fx);
|
||||
let res = match un_op {
|
||||
UnOp::Not => match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
||||
CValue::by_val(res, layout)
|
||||
UnOp::Not => {
|
||||
let val = operand.load_scalar(fx);
|
||||
match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
||||
CValue::by_val(res, layout)
|
||||
}
|
||||
ty::Uint(_) | ty::Int(_) => {
|
||||
CValue::by_val(fx.bcx.ins().bnot(val), layout)
|
||||
}
|
||||
_ => unreachable!("un op Not for {:?}", layout.ty),
|
||||
}
|
||||
ty::Uint(_) | ty::Int(_) => {
|
||||
CValue::by_val(fx.bcx.ins().bnot(val), layout)
|
||||
}
|
||||
UnOp::Neg => {
|
||||
let val = operand.load_scalar(fx);
|
||||
match layout.ty.kind() {
|
||||
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
|
||||
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
|
||||
_ => unreachable!("un op Neg for {:?}", layout.ty),
|
||||
}
|
||||
_ => unreachable!("un op Not for {:?}", layout.ty),
|
||||
},
|
||||
UnOp::Neg => match layout.ty.kind() {
|
||||
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
|
||||
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
|
||||
_ => unreachable!("un op Neg for {:?}", layout.ty),
|
||||
}
|
||||
UnOp::PtrMetadata => match layout.abi {
|
||||
Abi::Scalar(_) => CValue::zst(dest_layout),
|
||||
Abi::ScalarPair(_, _) => {
|
||||
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
|
||||
}
|
||||
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
|
||||
},
|
||||
};
|
||||
lval.write_cvalue(fx, res);
|
||||
|
|
@ -671,21 +677,22 @@ fn codegen_stmt<'tcx>(
|
|||
CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer),
|
||||
ref operand,
|
||||
to_ty,
|
||||
)
|
||||
| Rvalue::Cast(
|
||||
CastKind::PointerCoercion(PointerCoercion::MutToConstPointer),
|
||||
ref operand,
|
||||
to_ty,
|
||||
)
|
||||
| Rvalue::Cast(
|
||||
CastKind::PointerCoercion(PointerCoercion::ArrayToPointer),
|
||||
ref operand,
|
||||
to_ty,
|
||||
) => {
|
||||
let to_layout = fx.layout_of(fx.monomorphize(to_ty));
|
||||
let operand = codegen_operand(fx, operand);
|
||||
lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
|
||||
}
|
||||
Rvalue::Cast(
|
||||
CastKind::PointerCoercion(
|
||||
PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer,
|
||||
),
|
||||
..,
|
||||
) => {
|
||||
bug!(
|
||||
"{:?} is for borrowck, and should never appear in codegen",
|
||||
to_place_and_rval.1
|
||||
);
|
||||
}
|
||||
Rvalue::Cast(
|
||||
CastKind::IntToInt
|
||||
| CastKind::FloatToFloat
|
||||
|
|
@ -826,9 +833,10 @@ fn codegen_stmt<'tcx>(
|
|||
let val = match null_op {
|
||||
NullOp::SizeOf => layout.size.bytes(),
|
||||
NullOp::AlignOf => layout.align.abi.bytes(),
|
||||
NullOp::OffsetOf(fields) => {
|
||||
layout.offset_of_subfield(fx, fields.iter()).bytes()
|
||||
}
|
||||
NullOp::OffsetOf(fields) => fx
|
||||
.tcx
|
||||
.offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter())
|
||||
.bytes(),
|
||||
NullOp::UbChecks => {
|
||||
let val = fx.tcx.sess.ub_checks();
|
||||
let val = CValue::by_val(
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ pub(crate) fn maybe_codegen<'tcx>(
|
|||
}
|
||||
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
|
||||
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
|
||||
BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +133,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
Some(out_place.to_cvalue(fx))
|
||||
}
|
||||
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
|
||||
BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
|
||||
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
|
||||
BinOp::Div | BinOp::Rem => unreachable!(),
|
||||
BinOp::Cmp => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::sync::{Arc, Condvar, Mutex};
|
||||
|
||||
use jobserver::HelperThread;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_session::Session;
|
||||
|
||||
// FIXME don't panic when a worker thread panics
|
||||
|
|
@ -46,7 +47,7 @@ impl ConcurrencyLimiter {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn acquire(&self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken {
|
||||
pub(super) fn acquire(&self, dcx: DiagCtxtHandle<'_>) -> ConcurrencyLimiterToken {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
loop {
|
||||
state.assert_invariants();
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ pub(crate) fn codegen_tls_ref<'tcx>(
|
|||
) -> CValue<'tcx> {
|
||||
let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) {
|
||||
let instance = ty::Instance {
|
||||
def: ty::InstanceDef::ThreadLocalShim(def_id),
|
||||
def: ty::InstanceKind::ThreadLocalShim(def_id),
|
||||
args: ty::GenericArgs::empty(),
|
||||
};
|
||||
let func_ref = fx.get_function_ref(instance);
|
||||
|
|
@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>(
|
|||
assert!(layout.is_sized(), "unsized const value");
|
||||
|
||||
if layout.is_zst() {
|
||||
return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
|
||||
return CValue::zst(layout);
|
||||
}
|
||||
|
||||
match const_val {
|
||||
|
|
@ -110,7 +110,7 @@ pub(crate) fn codegen_const_value<'tcx>(
|
|||
if fx.clif_type(layout.ty).is_some() {
|
||||
return CValue::const_val(fx, layout, int);
|
||||
} else {
|
||||
let raw_val = int.size().truncate(int.assert_bits(int.size()));
|
||||
let raw_val = int.size().truncate(int.to_bits(int.size()));
|
||||
let val = match int.size().bytes() {
|
||||
1 => fx.bcx.ins().iconst(types::I8, raw_val as i64),
|
||||
2 => fx.bcx.ins().iconst(types::I16, raw_val as i64),
|
||||
|
|
@ -501,12 +501,12 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
|||
Ordering::Equal => scalar_int,
|
||||
Ordering::Less => match ty.kind() {
|
||||
ty::Uint(_) => ScalarInt::try_from_uint(
|
||||
scalar_int.assert_uint(scalar_int.size()),
|
||||
scalar_int.to_uint(scalar_int.size()),
|
||||
fx.layout_of(*ty).size,
|
||||
)
|
||||
.unwrap(),
|
||||
ty::Int(_) => ScalarInt::try_from_int(
|
||||
scalar_int.assert_int(scalar_int.size()),
|
||||
scalar_int.to_int(scalar_int.size()),
|
||||
fx.layout_of(*ty).size,
|
||||
)
|
||||
.unwrap(),
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ fn produce_final_output_artifacts(
|
|||
// to get rid of it.
|
||||
for output_type in crate_output.outputs.keys() {
|
||||
match *output_type {
|
||||
OutputType::Bitcode => {
|
||||
OutputType::Bitcode | OutputType::ThinLinkBitcode => {
|
||||
// Cranelift doesn't have bitcode
|
||||
// user_wants_bitcode = true;
|
||||
// // Copy to .bc, but always keep the .0.bc. There is a later
|
||||
|
|
@ -288,6 +288,29 @@ fn produce_final_output_artifacts(
|
|||
}
|
||||
}
|
||||
|
||||
if sess.opts.json_artifact_notifications {
|
||||
if codegen_results.modules.len() == 1 {
|
||||
codegen_results.modules[0].for_each_output(|_path, ty| {
|
||||
if sess.opts.output_types.contains_key(&ty) {
|
||||
let descr = ty.shorthand();
|
||||
// for single cgu file is renamed to drop cgu specific suffix
|
||||
// so we regenerate it the same way
|
||||
let path = crate_output.path(ty);
|
||||
sess.dcx().emit_artifact_notification(path.as_path(), descr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
for module in &codegen_results.modules {
|
||||
module.for_each_output(|path, ty| {
|
||||
if sess.opts.output_types.contains_key(&ty) {
|
||||
let descr = ty.shorthand();
|
||||
sess.dcx().emit_artifact_notification(&path, descr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We leave the following files around by default:
|
||||
// - #crate#.o
|
||||
// - #crate#.crate.metadata.o
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::fmt::Write;
|
|||
|
||||
use cranelift_codegen::isa::CallConv;
|
||||
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_span::sym;
|
||||
use rustc_target::asm::*;
|
||||
use target_lexicon::BinaryFormat;
|
||||
|
|
@ -927,7 +928,7 @@ fn call_inline_asm<'tcx>(
|
|||
fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option<types::Type> {
|
||||
match ty.kind() {
|
||||
// Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151
|
||||
ty::Adt(adt, args) if Some(adt.did()) == fx.tcx.lang_items().maybe_uninit() => {
|
||||
ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => {
|
||||
let fields = &adt.non_enum_variant().fields;
|
||||
let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args);
|
||||
let ty::Adt(ty, args) = ty.kind() else {
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
.span_fatal(span, "Index argument for `_mm_cmpestri` is not a constant");
|
||||
};
|
||||
|
||||
let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
|
||||
let imm8 = imm8.to_u8();
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
|
|
@ -955,7 +955,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
.span_fatal(span, "Index argument for `_mm_cmpestrm` is not a constant");
|
||||
};
|
||||
|
||||
let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
|
||||
let imm8 = imm8.to_u8();
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
|
|
@ -1003,7 +1003,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
);
|
||||
};
|
||||
|
||||
let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
|
||||
let imm8 = imm8.to_u8();
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
|
|
@ -1040,7 +1040,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
);
|
||||
};
|
||||
|
||||
let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
|
||||
let imm8 = imm8.to_u8();
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
|
|
@ -1195,7 +1195,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
.span_fatal(span, "Func argument for `_mm_sha1rnds4_epu32` is not a constant");
|
||||
};
|
||||
|
||||
let func = func.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", func));
|
||||
let func = func.to_u8();
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
|
|
|
|||
|
|
@ -1261,7 +1261,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
}
|
||||
|
||||
// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
|
||||
// by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`.
|
||||
// by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`.
|
||||
_ => {
|
||||
let intrinsic = fx.tcx.intrinsic(instance.def_id()).unwrap();
|
||||
if intrinsic.must_be_overridden {
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
.expect_const()
|
||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), span)
|
||||
.unwrap()
|
||||
.1
|
||||
.unwrap_branch();
|
||||
|
||||
assert_eq!(x.layout(), y.layout());
|
||||
|
|
@ -146,8 +147,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
|
||||
let total_len = lane_count * 2;
|
||||
|
||||
let indexes =
|
||||
idx.iter().map(|idx| idx.unwrap_leaf().try_to_u32().unwrap()).collect::<Vec<u32>>();
|
||||
let indexes = idx.iter().map(|idx| idx.unwrap_leaf().to_u32()).collect::<Vec<u32>>();
|
||||
|
||||
for &idx in &indexes {
|
||||
assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
|
||||
|
|
@ -281,9 +281,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
fx.tcx.dcx().span_fatal(span, "Index argument for `simd_insert` is not a constant");
|
||||
};
|
||||
|
||||
let idx: u32 = idx_const
|
||||
.try_to_u32()
|
||||
.unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const));
|
||||
let idx: u32 = idx_const.to_u32();
|
||||
let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
|
||||
if u64::from(idx) >= lane_count {
|
||||
fx.tcx.dcx().span_fatal(
|
||||
|
|
@ -329,9 +327,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
return;
|
||||
};
|
||||
|
||||
let idx = idx_const
|
||||
.try_to_u32()
|
||||
.unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const));
|
||||
let idx = idx_const.to_u32();
|
||||
let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
|
||||
if u64::from(idx) >= lane_count {
|
||||
fx.tcx.dcx().span_fatal(
|
||||
|
|
@ -348,6 +344,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
| sym::simd_bswap
|
||||
| sym::simd_bitreverse
|
||||
| sym::simd_ctlz
|
||||
| sym::simd_ctpop
|
||||
| sym::simd_cttz => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
|
|
@ -367,6 +364,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
(ty::Uint(_) | ty::Int(_), sym::simd_bswap) => fx.bcx.ins().bswap(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_bitreverse) => fx.bcx.ins().bitrev(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_ctlz) => fx.bcx.ins().clz(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_ctpop) => fx.bcx.ins().popcnt(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_cttz) => fx.bcx.ins().ctz(lane),
|
||||
|
||||
_ => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
#![cfg_attr(doc, allow(internal_features))]
|
||||
#![cfg_attr(doc, feature(rustdoc_internals))]
|
||||
#![cfg_attr(doc, doc(rust_logo))]
|
||||
#![feature(rustc_private)]
|
||||
// Note: please avoid adding other feature gates where possible
|
||||
// tidy-alphabetical-start
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(doc, allow(internal_features))]
|
||||
#![cfg_attr(doc, doc(rust_logo))]
|
||||
#![cfg_attr(doc, feature(rustdoc_internals))]
|
||||
// Note: please avoid adding other feature gates where possible
|
||||
#![feature(rustc_private)]
|
||||
// Note: please avoid adding other feature gates where possible
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![warn(unused_lifetimes)]
|
||||
#![warn(unreachable_pub)]
|
||||
#![warn(unused_lifetimes)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
extern crate jobserver;
|
||||
#[macro_use]
|
||||
|
|
@ -95,7 +98,7 @@ mod prelude {
|
|||
pub(crate) use rustc_middle::mir::{self, *};
|
||||
pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
pub(crate) use rustc_middle::ty::{
|
||||
self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, UintTy,
|
||||
self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy,
|
||||
};
|
||||
pub(crate) use rustc_span::Span;
|
||||
pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT};
|
||||
|
|
|
|||
|
|
@ -179,6 +179,9 @@ pub(crate) fn codegen_int_binop<'tcx>(
|
|||
}
|
||||
}
|
||||
BinOp::Offset => unreachable!("Offset is not an integer operation"),
|
||||
BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => {
|
||||
unreachable!("Overflow binops handled by `codegen_checked_int_binop`")
|
||||
}
|
||||
// Compare binops handles by `codegen_binop`.
|
||||
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
|
||||
unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
|
||||
|
|
|
|||
|
|
@ -39,8 +39,7 @@ pub(crate) fn unsized_info<'tcx>(
|
|||
}
|
||||
|
||||
// trait upcasting coercion
|
||||
let vptr_entry_idx =
|
||||
fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
|
||||
let vptr_entry_idx = fx.tcx.supertrait_vtable_slot((source, target));
|
||||
|
||||
if let Some(entry_idx) = vptr_entry_idx {
|
||||
let entry_idx = u32::try_from(entry_idx).unwrap();
|
||||
|
|
|
|||
|
|
@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> {
|
|||
CValue(CValueInner::ByValPair(value, extra), layout)
|
||||
}
|
||||
|
||||
/// Create an instance of a ZST
|
||||
///
|
||||
/// The is represented by a dangling pointer of suitable alignment.
|
||||
pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
|
||||
assert!(layout.is_zst());
|
||||
CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout)
|
||||
}
|
||||
|
||||
pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
self.1
|
||||
}
|
||||
|
|
@ -319,7 +327,7 @@ impl<'tcx> CValue<'tcx> {
|
|||
|
||||
let val = match layout.ty.kind() {
|
||||
ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
|
||||
let const_val = const_val.assert_bits(layout.size);
|
||||
let const_val = const_val.to_bits(layout.size);
|
||||
let lsb = fx.bcx.ins().iconst(types::I64, const_val as u64 as i64);
|
||||
let msb = fx.bcx.ins().iconst(types::I64, (const_val >> 64) as u64 as i64);
|
||||
fx.bcx.ins().iconcat(lsb, msb)
|
||||
|
|
@ -331,7 +339,7 @@ impl<'tcx> CValue<'tcx> {
|
|||
| ty::Ref(..)
|
||||
| ty::RawPtr(..)
|
||||
| ty::FnPtr(..) => {
|
||||
let raw_val = const_val.size().truncate(const_val.assert_bits(layout.size));
|
||||
let raw_val = const_val.size().truncate(const_val.to_bits(layout.size));
|
||||
fx.bcx.ins().iconst(clif_ty, raw_val as i64)
|
||||
}
|
||||
ty::Float(FloatTy::F32) => {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue