Auto merge of #17460 - lnicola:sync-from-rust, r=lnicola

minor: Sync from rust
This commit is contained in:
bors 2024-06-20 06:22:59 +00:00
commit f18fe6c437
4747 changed files with 87514 additions and 51808 deletions

12
.github/pull_request_template.md vendored Normal file
View 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 -->

View file

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

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

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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: &note_msg,
span,
},
);
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move,
ty,
place: &note_msg,
span,
});
} else {
err.subdiagnostic(
self.dcx(),
crate::session_diagnostics::TypeNoCopy::Note {
is_partial_move,
ty,
place: &note_msg,
},
);
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
is_partial_move,
ty,
place: &note_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!(

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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