Merge from rustc
This commit is contained in:
commit
08e774179e
926 changed files with 11732 additions and 10351 deletions
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
|
@ -294,7 +294,7 @@ jobs:
|
|||
- name: x86_64-gnu-integration
|
||||
env:
|
||||
CI_ONLY_WHEN_CHANNEL: nightly
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
os: ubuntu-20.04-8core-32gb
|
||||
- name: x86_64-gnu-debug
|
||||
os: ubuntu-20.04-8core-32gb
|
||||
env: {}
|
||||
|
|
@ -319,7 +319,7 @@ jobs:
|
|||
- name: dist-x86_64-apple
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
|
||||
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
|
||||
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.12
|
||||
SELECT_XCODE: /Applications/Xcode_13.4.1.app
|
||||
|
|
@ -332,7 +332,7 @@ jobs:
|
|||
- name: dist-apple-various
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
|
||||
RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
|
||||
RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.12
|
||||
SELECT_XCODE: /Applications/Xcode_13.4.1.app
|
||||
|
|
@ -343,7 +343,7 @@ jobs:
|
|||
- name: x86_64-apple-1
|
||||
env:
|
||||
SCRIPT: "./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.12
|
||||
MACOSX_STD_DEPLOYMENT_TARGET: 10.12
|
||||
|
|
@ -354,7 +354,7 @@ jobs:
|
|||
- name: x86_64-apple-2
|
||||
env:
|
||||
SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.12
|
||||
MACOSX_STD_DEPLOYMENT_TARGET: 10.12
|
||||
|
|
@ -365,7 +365,7 @@ jobs:
|
|||
- name: dist-aarch64-apple
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc"
|
||||
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
|
||||
SELECT_XCODE: /Applications/Xcode_13.4.1.app
|
||||
USE_XCODE_CLANG: 1
|
||||
|
|
|
|||
16
Cargo.lock
16
Cargo.lock
|
|
@ -37,9 +37,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -2169,9 +2169,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.153"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -6406,18 +6406,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.28"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d6f15f7ade05d2a4935e34a457b936c23dc70a05cc1d97133dc99e7a3fe0f0e"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.28"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbbad221e3f78500350ecbd7dfa4e63ef945c05f4c61cb7f4d3f84cd0bba649b"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
93
RELEASES.md
93
RELEASES.md
|
|
@ -1,3 +1,96 @@
|
|||
Version 1.76.0 (2024-02-08)
|
||||
==========================
|
||||
|
||||
<a id="1.76.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Document Rust ABI compatibility between various types](https://github.com/rust-lang/rust/pull/115476/)
|
||||
- [Also: guarantee that char and u32 are ABI-compatible](https://github.com/rust-lang/rust/pull/118032/)
|
||||
- [Warn against ambiguous wide pointer comparisons](https://github.com/rust-lang/rust/pull/117758/)
|
||||
|
||||
<a id="1.76.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Lint pinned `#[must_use]` pointers (in particular, `Box<T>` where `T` is `#[must_use]`) in `unused_must_use`.](https://github.com/rust-lang/rust/pull/118054/)
|
||||
- [Soundness fix: fix computing the offset of an unsized field in a packed struct](https://github.com/rust-lang/rust/pull/118540/)
|
||||
- [Soundness fix: fix dynamic size/align computation logic for packed types with dyn Trait tail](https://github.com/rust-lang/rust/pull/118538/)
|
||||
- [Add `$message_type` field to distinguish json diagnostic outputs](https://github.com/rust-lang/rust/pull/115691/)
|
||||
- [Enable Rust to use the EHCont security feature of Windows](https://github.com/rust-lang/rust/pull/118013/)
|
||||
- [Add tier 3 {x86_64,i686}-win7-windows-msvc targets](https://github.com/rust-lang/rust/pull/118150/)
|
||||
- [Add tier 3 aarch64-apple-watchos target](https://github.com/rust-lang/rust/pull/119074/)
|
||||
- [Add tier 3 arm64e-apple-ios & arm64e-apple-darwin targets](https://github.com/rust-lang/rust/pull/115526/)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.76.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Add a column number to `dbg!()`](https://github.com/rust-lang/rust/pull/114962/)
|
||||
- [Add `std::hash::{DefaultHasher, RandomState}` exports](https://github.com/rust-lang/rust/pull/115694/)
|
||||
- [Fix rounding issue with exponents in fmt](https://github.com/rust-lang/rust/pull/116301/)
|
||||
- [Add T: ?Sized to `RwLockReadGuard` and `RwLockWriteGuard`'s Debug impls.](https://github.com/rust-lang/rust/pull/117138/)
|
||||
- [Windows: Allow `File::create` to work on hidden files](https://github.com/rust-lang/rust/pull/116438/)
|
||||
|
||||
<a id="1.76.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`Arc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.unwrap_or_clone)
|
||||
- [`Rc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.unwrap_or_clone)
|
||||
- [`Result::inspect`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect)
|
||||
- [`Result::inspect_err`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect_err)
|
||||
- [`Option::inspect`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.inspect)
|
||||
- [`type_name_of_val`](https://doc.rust-lang.org/stable/std/any/fn.type_name_of_val.html)
|
||||
- [`std::hash::{DefaultHasher, RandomState}`](https://doc.rust-lang.org/stable/std/hash/index.html#structs)
|
||||
These were previously available only through `std::collections::hash_map`.
|
||||
- [`ptr::{from_ref, from_mut}`](https://doc.rust-lang.org/stable/std/ptr/fn.from_ref.html)
|
||||
- [`ptr::addr_eq`](https://doc.rust-lang.org/stable/std/ptr/fn.addr_eq.html)
|
||||
|
||||
<a id="1.76.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
See [Cargo release notes](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-176-2024-02-08).
|
||||
|
||||
<a id="1.76.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-------
|
||||
|
||||
- [Don't merge cfg and doc(cfg) attributes for re-exports](https://github.com/rust-lang/rust/pull/113091/)
|
||||
- [rustdoc: allow resizing the sidebar / hiding the top bar](https://github.com/rust-lang/rust/pull/115660/)
|
||||
- [rustdoc-search: add support for traits and associated types](https://github.com/rust-lang/rust/pull/116085/)
|
||||
- [rustdoc: Add highlighting for comments in items declaration](https://github.com/rust-lang/rust/pull/117869/)
|
||||
|
||||
<a id="1.76.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Add allow-by-default lint for unit bindings](https://github.com/rust-lang/rust/pull/112380/)
|
||||
This is expected to be upgraded to a warning by default in a future Rust
|
||||
release. Some macros emit bindings with type `()` with user-provided spans,
|
||||
which means that this lint will warn for user code.
|
||||
- [Remove x86_64-sun-solaris target.](https://github.com/rust-lang/rust/pull/118091/)
|
||||
- [Remove asmjs-unknown-emscripten target](https://github.com/rust-lang/rust/pull/117338/)
|
||||
- [Report errors in jobserver inherited through environment variables](https://github.com/rust-lang/rust/pull/113730/)
|
||||
This [may warn](https://github.com/rust-lang/rust/issues/120515) on benign problems too.
|
||||
- [Update the minimum external LLVM to 16.](https://github.com/rust-lang/rust/pull/117947/)
|
||||
- [Improve `print_tts`](https://github.com/rust-lang/rust/pull/114571/)
|
||||
This change can break some naive manual parsing of token trees in proc macro
|
||||
code which expect a particular structure after `.to_string()`, rather than just arbitrary Rust code.
|
||||
- [Make `IMPLIED_BOUNDS_ENTAILMENT` into a hard error from a lint](https://github.com/rust-lang/rust/pull/117984/)
|
||||
- [Vec's allocation behavior was changed when collecting some iterators](https://github.com/rust-lang/rust/pull/110353)
|
||||
Allocation behavior is currently not specified, nevertheless changes can be surprising.
|
||||
See [`impl FromIterator for Vec`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#impl-FromIterator%3CT%3E-for-Vec%3CT%3E)
|
||||
for more details.
|
||||
- [Properly reject `default` on free const items](https://github.com/rust-lang/rust/pull/117818/)
|
||||
|
||||
Version 1.75.0 (2023-12-28)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
|
|
@ -291,12 +291,16 @@ pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
pub struct TraitBoundModifiers {
|
||||
pub constness: BoundConstness,
|
||||
pub asyncness: BoundAsyncness,
|
||||
pub polarity: BoundPolarity,
|
||||
}
|
||||
|
||||
impl TraitBoundModifiers {
|
||||
pub const NONE: Self =
|
||||
Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
|
||||
pub const NONE: Self = Self {
|
||||
constness: BoundConstness::Never,
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
polarity: BoundPolarity::Positive,
|
||||
};
|
||||
}
|
||||
|
||||
/// The AST represents all type param bounds as types.
|
||||
|
|
@ -2562,6 +2566,25 @@ impl BoundConstness {
|
|||
}
|
||||
}
|
||||
|
||||
/// The asyncness of a trait bound.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum BoundAsyncness {
|
||||
/// `Type: Trait`
|
||||
Normal,
|
||||
/// `Type: async Trait`
|
||||
Async(Span),
|
||||
}
|
||||
|
||||
impl BoundAsyncness {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Normal => "",
|
||||
Self::Async(_) => "async",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum FnRetTy {
|
||||
/// Returns type is not specified.
|
||||
|
|
@ -3300,7 +3323,7 @@ mod size_asserts {
|
|||
static_assert_size!(ForeignItem, 96);
|
||||
static_assert_size!(ForeignItemKind, 24);
|
||||
static_assert_size!(GenericArg, 24);
|
||||
static_assert_size!(GenericBound, 72);
|
||||
static_assert_size!(GenericBound, 88);
|
||||
static_assert_size!(Generics, 40);
|
||||
static_assert_size!(Impl, 136);
|
||||
static_assert_size!(Item, 136);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ ast_lowering_argument = argument
|
|||
ast_lowering_assoc_ty_parentheses =
|
||||
parenthesized generic arguments cannot be used in associated type constraints
|
||||
|
||||
ast_lowering_async_bound_not_on_trait =
|
||||
`async` bound modifier only allowed on trait, not `{$descr}`
|
||||
|
||||
ast_lowering_async_bound_only_for_fn_traits =
|
||||
`async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits
|
||||
|
||||
ast_lowering_async_coroutines_not_supported =
|
||||
`async` coroutines are not yet supported
|
||||
|
||||
|
|
|
|||
|
|
@ -395,3 +395,18 @@ pub(crate) struct GenericParamDefaultInBinder {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_bound_not_on_trait)]
|
||||
pub(crate) struct AsyncBoundNotOnTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub descr: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_bound_only_for_fn_traits)]
|
||||
pub(crate) struct AsyncBoundOnlyForFnTraits {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ParenthesizedGenericArgs::Err,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
// Method calls can't have bound modifiers
|
||||
None,
|
||||
));
|
||||
let receiver = self.lower_expr(receiver);
|
||||
let args =
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub(super) struct ItemLowerer<'a, 'hir> {
|
|||
pub(super) tcx: TyCtxt<'hir>,
|
||||
pub(super) resolver: &'a mut ResolverAstLowering,
|
||||
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>,
|
||||
}
|
||||
|
||||
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
|
||||
|
|
@ -64,10 +64,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_node(
|
||||
&mut self,
|
||||
def_id: LocalDefId,
|
||||
) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
|
||||
pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
if let hir::MaybeOwner::Phantom = owner {
|
||||
let node = self.ast_index[def_id];
|
||||
|
|
@ -343,14 +340,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
|
||||
let constness = match *constness {
|
||||
Const::Yes(span) => BoundConstness::Maybe(span),
|
||||
Const::No => BoundConstness::Never,
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: match *constness {
|
||||
Const::Yes(span) => BoundConstness::Maybe(span),
|
||||
Const::No => BoundConstness::Never,
|
||||
},
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
// we don't use this in bound lowering
|
||||
polarity: BoundPolarity::Positive,
|
||||
};
|
||||
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
constness,
|
||||
modifiers,
|
||||
trait_ref,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ struct LoweringContext<'a, 'hir> {
|
|||
/// Attributes inside the owner being lowered.
|
||||
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
|
||||
/// Collect items that were created by lowering the current owner.
|
||||
children: Vec<(LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>)>,
|
||||
children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>,
|
||||
|
||||
coroutine_kind: Option<hir::CoroutineKind>,
|
||||
|
||||
|
|
@ -131,6 +131,7 @@ struct LoweringContext<'a, 'hir> {
|
|||
allow_gen_future: Lrc<[Symbol]>,
|
||||
allow_async_iterator: Lrc<[Symbol]>,
|
||||
allow_for_await: Lrc<[Symbol]>,
|
||||
allow_async_fn_traits: Lrc<[Symbol]>,
|
||||
|
||||
/// Mapping from generics `def_id`s to TAIT generics `def_id`s.
|
||||
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
|
||||
|
|
@ -176,6 +177,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
[sym::gen_future].into()
|
||||
},
|
||||
allow_for_await: [sym::async_iterator].into(),
|
||||
allow_async_fn_traits: [sym::async_fn_traits].into(),
|
||||
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
|
||||
// interact with `gen`/`async gen` blocks
|
||||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
|
|
@ -415,7 +417,7 @@ fn index_crate<'a>(
|
|||
/// This hash will then be part of the crate_hash which is stored in the metadata.
|
||||
fn compute_hir_hash(
|
||||
tcx: TyCtxt<'_>,
|
||||
owners: &IndexSlice<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
|
||||
owners: &IndexSlice<LocalDefId, hir::MaybeOwner<'_>>,
|
||||
) -> Fingerprint {
|
||||
let mut hir_body_nodes: Vec<_> = owners
|
||||
.iter_enumerated()
|
||||
|
|
@ -1311,7 +1313,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: t.span,
|
||||
},
|
||||
itctx,
|
||||
ast::BoundConstness::Never,
|
||||
TraitBoundModifiers::NONE,
|
||||
);
|
||||
let bounds = this.arena.alloc_from_iter([bound]);
|
||||
let lifetime_bound = this.elided_dyn_bound(t.span);
|
||||
|
|
@ -1426,7 +1428,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
itctx,
|
||||
// Still, don't pass along the constness here; we don't want to
|
||||
// synthesize any host effect args, it'd only cause problems.
|
||||
ast::BoundConstness::Never,
|
||||
TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
..*modifiers
|
||||
},
|
||||
))
|
||||
}
|
||||
BoundPolarity::Maybe(_) => None,
|
||||
|
|
@ -2019,7 +2024,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> hir::GenericBound<'hir> {
|
||||
match tpb {
|
||||
GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
|
||||
self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()),
|
||||
self.lower_poly_trait_ref(p, itctx, *modifiers),
|
||||
self.lower_trait_bound_modifiers(*modifiers),
|
||||
),
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
|
|
@ -2192,7 +2197,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
fn lower_trait_ref(
|
||||
&mut self,
|
||||
constness: ast::BoundConstness,
|
||||
modifiers: ast::TraitBoundModifiers,
|
||||
p: &TraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
) -> hir::TraitRef<'hir> {
|
||||
|
|
@ -2202,7 +2207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&p.path,
|
||||
ParamMode::Explicit,
|
||||
itctx,
|
||||
Some(constness),
|
||||
Some(modifiers),
|
||||
) {
|
||||
hir::QPath::Resolved(None, path) => path,
|
||||
qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
|
||||
|
|
@ -2215,11 +2220,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
p: &PolyTraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: ast::BoundConstness,
|
||||
modifiers: ast::TraitBoundModifiers,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
let bound_generic_params =
|
||||
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
|
||||
let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
|
||||
let trait_ref = self.lower_trait_ref(modifiers, &p.trait_ref, itctx);
|
||||
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
use crate::ImplTraitPosition;
|
||||
|
||||
use super::errors::{GenericTypeWithParentheses, UseAngleBrackets};
|
||||
use super::errors::{
|
||||
AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, GenericTypeWithParentheses, UseAngleBrackets,
|
||||
};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, PartialRes, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
|
|
@ -24,8 +28,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
// constness of the impl/bound if this is a trait path
|
||||
constness: Option<ast::BoundConstness>,
|
||||
// modifiers of the impl/bound if this is a trait path
|
||||
modifiers: Option<ast::TraitBoundModifiers>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
|
|
@ -35,10 +39,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let base_res = partial_res.base_res();
|
||||
let unresolved_segments = partial_res.unresolved_segments();
|
||||
|
||||
let mut res = self.lower_res(base_res);
|
||||
|
||||
// When we have an `async` kw on a bound, map the trait it resolves to.
|
||||
let mut bound_modifier_allowed_features = None;
|
||||
if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers {
|
||||
match res {
|
||||
Res::Def(DefKind::Trait, def_id) => {
|
||||
if let Some((async_def_id, features)) = self.map_trait_to_async_trait(def_id) {
|
||||
res = Res::Def(DefKind::Trait, async_def_id);
|
||||
bound_modifier_allowed_features = Some(features);
|
||||
} else {
|
||||
self.dcx().emit_err(AsyncBoundOnlyForFnTraits { span: p.span });
|
||||
}
|
||||
}
|
||||
Res::Err => {
|
||||
// No additional error.
|
||||
}
|
||||
_ => {
|
||||
// This error isn't actually emitted AFAICT, but it's best to keep
|
||||
// it around in case the resolver doesn't always check the defkind
|
||||
// of an item or something.
|
||||
self.dcx().emit_err(AsyncBoundNotOnTrait { span: p.span, descr: res.descr() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let path_span_lo = p.span.shrink_to_lo();
|
||||
let proj_start = p.segments.len() - unresolved_segments;
|
||||
let path = self.arena.alloc(hir::Path {
|
||||
res: self.lower_res(base_res),
|
||||
res,
|
||||
segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
|
||||
|(i, segment)| {
|
||||
let param_mode = match (qself_position, param_mode) {
|
||||
|
|
@ -77,7 +107,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
parenthesized_generic_args,
|
||||
itctx,
|
||||
// if this is the last segment, add constness to the trait path
|
||||
if i == proj_start - 1 { constness } else { None },
|
||||
if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None },
|
||||
bound_modifier_allowed_features.clone(),
|
||||
)
|
||||
},
|
||||
)),
|
||||
|
|
@ -88,6 +119,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
),
|
||||
});
|
||||
|
||||
if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
|
||||
path.span = self.mark_span_with_reason(
|
||||
DesugaringKind::BoundModifier,
|
||||
path.span,
|
||||
Some(bound_modifier_allowed_features),
|
||||
);
|
||||
}
|
||||
|
||||
// Simple case, either no projections, or only fully-qualified.
|
||||
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
|
||||
if unresolved_segments == 0 {
|
||||
|
|
@ -125,6 +164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ParenthesizedGenericArgs::Err,
|
||||
itctx,
|
||||
None,
|
||||
None,
|
||||
));
|
||||
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
|
||||
|
||||
|
|
@ -166,6 +206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ParenthesizedGenericArgs::Err,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
})),
|
||||
span: self.lower_span(p.span),
|
||||
|
|
@ -180,6 +221,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
// Additional features ungated with a bound modifier like `async`.
|
||||
// This is passed down to the implicit associated type binding in
|
||||
// parenthesized bounds.
|
||||
bound_modifier_allowed_features: Option<Lrc<[Symbol]>>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
|
||||
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
|
||||
|
|
@ -188,9 +233,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
|
||||
}
|
||||
GenericArgs::Parenthesized(data) => match parenthesized_generic_args {
|
||||
ParenthesizedGenericArgs::ParenSugar => {
|
||||
self.lower_parenthesized_parameter_data(data, itctx)
|
||||
}
|
||||
ParenthesizedGenericArgs::ParenSugar => self
|
||||
.lower_parenthesized_parameter_data(
|
||||
data,
|
||||
itctx,
|
||||
bound_modifier_allowed_features,
|
||||
),
|
||||
ParenthesizedGenericArgs::Err => {
|
||||
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
|
||||
let sub = if !data.inputs.is_empty() {
|
||||
|
|
@ -357,6 +405,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
data: &ParenthesizedArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
bound_modifier_allowed_features: Option<Lrc<[Symbol]>>,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
// Switch to `PassThrough` mode for anonymous lifetimes; this
|
||||
// means that we permit things like `&Ref<T>`, where `Ref` has
|
||||
|
|
@ -392,7 +441,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
|
||||
let binding = self.assoc_ty_binding(sym::Output, output_ty.span, output_ty);
|
||||
|
||||
// If we have a bound like `async Fn() -> T`, make sure that we mark the
|
||||
// `Output = T` associated type bound with the right feature gates.
|
||||
let mut output_span = output_ty.span;
|
||||
if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
|
||||
output_span = self.mark_span_with_reason(
|
||||
DesugaringKind::BoundModifier,
|
||||
output_span,
|
||||
Some(bound_modifier_allowed_features),
|
||||
);
|
||||
}
|
||||
let binding = self.assoc_ty_binding(sym::Output, output_span, output_ty);
|
||||
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args,
|
||||
|
|
@ -429,4 +490,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
/// When a bound is annotated with `async`, it signals to lowering that the trait
|
||||
/// that the bound refers to should be mapped to the "async" flavor of the trait.
|
||||
///
|
||||
/// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one
|
||||
/// that is generic over `async`ness, if that's ever possible, or modify the
|
||||
/// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
|
||||
fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<(DefId, Lrc<[Symbol]>)> {
|
||||
let lang_items = self.tcx.lang_items();
|
||||
if Some(def_id) == lang_items.fn_trait() {
|
||||
Some((lang_items.async_fn_trait()?, self.allow_async_fn_traits.clone()))
|
||||
} else if Some(def_id) == lang_items.fn_mut_trait() {
|
||||
Some((lang_items.async_fn_mut_trait()?, self.allow_async_fn_traits.clone()))
|
||||
} else if Some(def_id) == lang_items.fn_once_trait() {
|
||||
Some((lang_items.async_fn_once_trait()?, self.allow_async_fn_traits.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -362,6 +362,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_generic_args(&mut self, args: &'a ast::GenericArgs) {
|
||||
// This check needs to happen here because the never type can be returned from a function,
|
||||
// but cannot be used in any other context. If this check was in `visit_fn_ret_ty`, it
|
||||
// include both functions and generics like `impl Fn() -> !`.
|
||||
if let ast::GenericArgs::Parenthesized(generic_args) = args
|
||||
&& let ast::FnRetTy::Ty(ref ty) = generic_args.output
|
||||
&& matches!(ty.kind, ast::TyKind::Never)
|
||||
{
|
||||
gate!(&self, never_type, ty.span, "the `!` type is experimental");
|
||||
}
|
||||
visit::walk_generic_args(self, args);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||
match e.kind {
|
||||
ast::ExprKind::TryBlock(_) => {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ mod item;
|
|||
use crate::pp::Breaks::{Consistent, Inconsistent};
|
||||
use crate::pp::{self, Breaks};
|
||||
use crate::pprust::state::expr::FixupContext;
|
||||
use ast::TraitBoundModifiers;
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
|
||||
|
|
@ -1590,18 +1591,28 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
match bound {
|
||||
GenericBound::Trait(tref, modifier) => {
|
||||
match modifier.constness {
|
||||
GenericBound::Trait(
|
||||
tref,
|
||||
TraitBoundModifiers { constness, asyncness, polarity },
|
||||
) => {
|
||||
match constness {
|
||||
ast::BoundConstness::Never => {}
|
||||
ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
|
||||
self.word_space(modifier.constness.as_str());
|
||||
self.word_space(constness.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
match modifier.polarity {
|
||||
match asyncness {
|
||||
ast::BoundAsyncness::Normal => {}
|
||||
ast::BoundAsyncness::Async(_) => {
|
||||
self.word_space(asyncness.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
match polarity {
|
||||
ast::BoundPolarity::Positive => {}
|
||||
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
|
||||
self.word(modifier.polarity.as_str());
|
||||
self.word(polarity.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
noun_old: &str,
|
||||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
|
|
@ -162,7 +162,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
second_borrow_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
|
|
@ -194,7 +194,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
kind_old: &str,
|
||||
msg_old: &str,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
|
|
@ -235,7 +235,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
span: Span,
|
||||
borrow_span: Span,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
|
|
@ -252,7 +252,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
span: Span,
|
||||
desc: &str,
|
||||
is_arg: bool,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
|
||||
struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc)
|
||||
}
|
||||
|
|
@ -265,7 +265,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&self,
|
||||
move_from_span: Span,
|
||||
move_from_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
move_from_span,
|
||||
|
|
@ -283,7 +283,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
move_from_span: Span,
|
||||
ty: Ty<'_>,
|
||||
is_index: Option<bool>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let type_name = match (&ty.kind(), is_index) {
|
||||
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
||||
(&ty::Slice(_), _) => "slice",
|
||||
|
|
@ -304,7 +304,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&self,
|
||||
move_from_span: Span,
|
||||
container_ty: Ty<'_>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
move_from_span,
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&mut self,
|
||||
mpi: MovePathIndex,
|
||||
move_span: Span,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
in_pattern: &mut bool,
|
||||
move_spans: UseSpans<'_>,
|
||||
) {
|
||||
|
|
@ -486,7 +486,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
desired_action: InitializationRequiringAction,
|
||||
span: Span,
|
||||
use_spans: UseSpans<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
// We need all statements in the body where the binding was assigned to later find all
|
||||
// the branching code paths where the binding *wasn't* assigned to.
|
||||
let inits = &self.move_data.init_path_map[mpi];
|
||||
|
|
@ -880,7 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
location: Location,
|
||||
(place, _span): (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.args_or_use();
|
||||
|
||||
|
|
@ -930,7 +930,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
(place, span): (Place<'tcx>, Span),
|
||||
gen_borrow_kind: BorrowKind,
|
||||
issued_borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
|
||||
let issued_span = issued_spans.args_or_use();
|
||||
|
||||
|
|
@ -2129,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
drop_span: Span,
|
||||
borrow_spans: UseSpans<'tcx>,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
debug!(
|
||||
"report_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}, {:?}\
|
||||
|
|
@ -2304,7 +2304,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&mut self,
|
||||
drop_span: Span,
|
||||
borrow_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
debug!(
|
||||
"report_thread_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}\
|
||||
|
|
@ -2329,7 +2329,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
borrow_spans: UseSpans<'tcx>,
|
||||
proper_span: Span,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
|
||||
explanation
|
||||
{
|
||||
|
|
@ -2440,7 +2440,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"consider consuming the `{ty}` when turning it into an \
|
||||
`Iterator`",
|
||||
),
|
||||
"into_iter".to_string(),
|
||||
"into_iter",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
|
@ -2496,7 +2496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return_span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
opt_place_desc: Option<&String>,
|
||||
) -> Option<DiagnosticBuilder<'cx>> {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let return_kind = match category {
|
||||
ConstraintCategory::Return(_) => "return",
|
||||
ConstraintCategory::Yield => "yield",
|
||||
|
|
@ -2591,7 +2591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
constraint_span: Span,
|
||||
captured_var: &str,
|
||||
scope: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let args_span = use_span.args_or_use();
|
||||
|
||||
|
|
@ -2699,7 +2699,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
upvar_span: Span,
|
||||
upvar_name: Symbol,
|
||||
escape_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id());
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
&mut self,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let description = if place.projection.len() == 1 {
|
||||
format!("static item {}", self.describe_any_place(place.as_ref()))
|
||||
} else {
|
||||
|
|
@ -310,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
deref_target_place: Place<'tcx>,
|
||||
span: Span,
|
||||
use_spans: Option<UseSpans<'tcx>>,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
// Inspect the type of the content behind the
|
||||
// borrow to provide feedback about why this
|
||||
// was a move rather than a copy.
|
||||
|
|
|
|||
|
|
@ -198,12 +198,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
{
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
mut_error = Some(span);
|
||||
if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
|
||||
if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) {
|
||||
// We've encountered a second (or more) attempt to mutably borrow an
|
||||
// immutable binding, so the likely problem is with the binding
|
||||
// declaration, not the use. We collect these in a single diagnostic
|
||||
// and make the binding the primary span of the error.
|
||||
err = buffer;
|
||||
err = buffered_err;
|
||||
count = c + 1;
|
||||
if count == 2 {
|
||||
err.replace_span_with(span, false);
|
||||
|
|
@ -924,7 +924,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"use a mutable iterator instead",
|
||||
"mut ".to_string(),
|
||||
"mut ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,6 +251,6 @@ impl OutlivesSuggestionBuilder {
|
|||
diag.sort_span = mir_span.shrink_to_hi();
|
||||
|
||||
// Buffer the diagnostic
|
||||
mbcx.buffer_non_error_diag(diag);
|
||||
mbcx.buffer_non_error(diag);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ extern crate tracing;
|
|||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
|
||||
|
|
@ -173,12 +173,11 @@ fn do_mir_borrowck<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let mut errors = error::BorrowckErrors::new(infcx.tcx);
|
||||
let mut diags = diags::BorrowckDiags::new();
|
||||
|
||||
// Gather the upvars of a closure, if any.
|
||||
if let Some(e) = input_body.tainted_by_errors {
|
||||
infcx.set_tainted_by_errors(e);
|
||||
errors.set_tainted_by_errors(e);
|
||||
}
|
||||
|
||||
// Replace all regions with fresh inference variables. This
|
||||
|
|
@ -244,7 +243,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
®ioncx,
|
||||
&opt_closure_req,
|
||||
&opaque_type_values,
|
||||
&mut errors,
|
||||
&mut diags,
|
||||
);
|
||||
|
||||
// The various `flow_*` structures can be large. We drop `flow_inits` here
|
||||
|
|
@ -305,11 +304,11 @@ fn do_mir_borrowck<'tcx>(
|
|||
next_region_name: RefCell::new(1),
|
||||
polonius_output: None,
|
||||
move_errors: Vec::new(),
|
||||
errors,
|
||||
diags,
|
||||
};
|
||||
MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
|
||||
promoted_mbcx.report_move_errors();
|
||||
errors = promoted_mbcx.errors;
|
||||
diags = promoted_mbcx.diags;
|
||||
|
||||
struct MoveVisitor<'a, 'cx, 'tcx> {
|
||||
ctxt: &'a mut MirBorrowckCtxt<'cx, 'tcx>,
|
||||
|
|
@ -346,7 +345,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
next_region_name: RefCell::new(1),
|
||||
polonius_output,
|
||||
move_errors: Vec::new(),
|
||||
errors,
|
||||
diags,
|
||||
};
|
||||
|
||||
// Compute and report region errors, if any.
|
||||
|
|
@ -574,7 +573,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
|
|||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
|
||||
errors: error::BorrowckErrors<'tcx>,
|
||||
diags: diags::BorrowckDiags<'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
}
|
||||
|
||||
|
|
@ -2125,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
||||
) => {
|
||||
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
|
||||
&& !self.has_buffered_errors()
|
||||
&& !self.has_buffered_diags()
|
||||
{
|
||||
// rust-lang/rust#46908: In pure NLL mode this code path should be
|
||||
// unreachable, but we use `span_delayed_bug` because we can hit this when
|
||||
|
|
@ -2383,17 +2382,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
mod error {
|
||||
mod diags {
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct BorrowckErrors<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
enum BufferedDiag<'tcx> {
|
||||
Error(DiagnosticBuilder<'tcx>),
|
||||
NonError(DiagnosticBuilder<'tcx, ()>),
|
||||
}
|
||||
|
||||
impl<'tcx> BufferedDiag<'tcx> {
|
||||
fn sort_span(&self) -> Span {
|
||||
match self {
|
||||
BufferedDiag::Error(diag) => diag.sort_span,
|
||||
BufferedDiag::NonError(diag) => diag.sort_span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BorrowckDiags<'tcx> {
|
||||
/// This field keeps track of move errors that are to be reported for given move indices.
|
||||
///
|
||||
/// There are situations where many errors can be reported for a single move out (see #53807)
|
||||
/// and we want only the best of those errors.
|
||||
/// There are situations where many errors can be reported for a single move out (see
|
||||
/// #53807) and we want only the best of those errors.
|
||||
///
|
||||
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
|
||||
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
|
||||
|
|
@ -2406,51 +2418,38 @@ mod error {
|
|||
/// same primary span come out in a consistent order.
|
||||
buffered_move_errors:
|
||||
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
|
||||
|
||||
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx>, usize)>,
|
||||
/// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder`
|
||||
/// because it has a mixture of error diagnostics and non-error diagnostics.
|
||||
buffered: Vec<Diagnostic>,
|
||||
/// Set to Some if we emit an error during borrowck
|
||||
tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
|
||||
/// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
|
||||
buffered_diags: Vec<BufferedDiag<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> BorrowckErrors<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
BorrowckErrors {
|
||||
tcx,
|
||||
impl<'tcx> BorrowckDiags<'tcx> {
|
||||
pub fn new() -> Self {
|
||||
BorrowckDiags {
|
||||
buffered_move_errors: BTreeMap::new(),
|
||||
buffered_mut_errors: Default::default(),
|
||||
buffered: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
buffered_diags: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
if let None = self.tainted_by_errors {
|
||||
self.tainted_by_errors = Some(self.tcx.dcx().span_delayed_bug(
|
||||
t.span.clone_ignoring_labels(),
|
||||
"diagnostic buffered but not emitted",
|
||||
))
|
||||
}
|
||||
self.buffered.push(t.into_diagnostic());
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) {
|
||||
self.buffered_diags.push(BufferedDiag::Error(t));
|
||||
}
|
||||
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
|
||||
self.buffered.push(t.into_diagnostic());
|
||||
}
|
||||
|
||||
pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
|
||||
self.tainted_by_errors = Some(e);
|
||||
pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) {
|
||||
self.buffered_diags.push(BufferedDiag::NonError(t));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
self.errors.buffer_error(t);
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) {
|
||||
self.diags.buffer_error(t);
|
||||
}
|
||||
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
|
||||
self.errors.buffer_non_error_diag(t);
|
||||
pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) {
|
||||
self.diags.buffer_non_error(t);
|
||||
}
|
||||
|
||||
pub fn buffer_move_error(
|
||||
|
|
@ -2459,7 +2458,7 @@ mod error {
|
|||
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
|
||||
) -> bool {
|
||||
if let Some((_, diag)) =
|
||||
self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
self.diags.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
{
|
||||
// Cancel the old diagnostic so we don't ICE
|
||||
diag.cancel();
|
||||
|
|
@ -2473,47 +2472,50 @@ mod error {
|
|||
&mut self,
|
||||
span: Span,
|
||||
) -> Option<(DiagnosticBuilder<'tcx>, usize)> {
|
||||
self.errors.buffered_mut_errors.remove(&span)
|
||||
self.diags.buffered_mut_errors.remove(&span)
|
||||
}
|
||||
|
||||
pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) {
|
||||
self.errors.buffered_mut_errors.insert(span, (t, count));
|
||||
self.diags.buffered_mut_errors.insert(span, (t, count));
|
||||
}
|
||||
|
||||
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
|
||||
let mut res = None;
|
||||
|
||||
// Buffer any move errors that we collected and de-duplicated.
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
|
||||
// We have already set tainted for this error, so just buffer it.
|
||||
self.errors.buffered.push(diag.into_diagnostic());
|
||||
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
|
||||
}
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
|
||||
if count > 10 {
|
||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||
}
|
||||
self.errors.buffered.push(diag.into_diagnostic());
|
||||
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
|
||||
}
|
||||
|
||||
if !self.errors.buffered.is_empty() {
|
||||
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
|
||||
|
||||
let dcx = self.dcx();
|
||||
for diag in self.errors.buffered.drain(..) {
|
||||
dcx.emit_diagnostic(diag);
|
||||
if !self.diags.buffered_diags.is_empty() {
|
||||
self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
|
||||
for buffered_diag in self.diags.buffered_diags.drain(..) {
|
||||
match buffered_diag {
|
||||
BufferedDiag::Error(diag) => res = Some(diag.emit()),
|
||||
BufferedDiag::NonError(diag) => diag.emit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.errors.tainted_by_errors
|
||||
res
|
||||
}
|
||||
|
||||
pub fn has_buffered_errors(&self) -> bool {
|
||||
self.errors.buffered.is_empty()
|
||||
pub(crate) fn has_buffered_diags(&self) -> bool {
|
||||
self.diags.buffered_diags.is_empty()
|
||||
}
|
||||
|
||||
pub fn has_move_error(
|
||||
&self,
|
||||
move_out_indices: &[MoveOutIndex],
|
||||
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
|
||||
self.errors.buffered_move_errors.get(move_out_indices)
|
||||
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)> {
|
||||
self.diags.buffered_move_errors.get(move_out_indices)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ pub(super) fn dump_annotation<'tcx>(
|
|||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
errors: &mut crate::error::BorrowckErrors<'tcx>,
|
||||
diags: &mut crate::diags::BorrowckDiags<'tcx>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
|
|
@ -310,7 +310,7 @@ pub(super) fn dump_annotation<'tcx>(
|
|||
err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}"));
|
||||
}
|
||||
|
||||
errors.buffer_non_error_diag(err);
|
||||
diags.buffer_non_error(err);
|
||||
}
|
||||
|
||||
fn for_each_region_constraint<'tcx>(
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -293,6 +294,24 @@ version = "1.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.9.3"
|
||||
|
|
@ -360,12 +379,29 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
|
@ -536,3 +572,23 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -56,11 +56,7 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call
|
|||
sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented");
|
||||
}
|
||||
|
||||
Conv::Msp430Intr
|
||||
| Conv::PtxKernel
|
||||
| Conv::AmdGpuKernel
|
||||
| Conv::AvrInterrupt
|
||||
| Conv::AvrNonBlockingInterrupt => {
|
||||
Conv::Msp430Intr | Conv::PtxKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => {
|
||||
unreachable!("tried to use {c:?} call conv which only exists on an unsupported target");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &Locke
|
|||
.filter(|_feature| {
|
||||
target_info.cpu_supports(_feature)
|
||||
/*
|
||||
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma,
|
||||
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
|
||||
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
|
||||
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
|
||||
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
|
||||
|
|
|
|||
|
|
@ -590,7 +590,6 @@ impl From<Conv> for llvm::CallConv {
|
|||
Conv::Cold => llvm::ColdCallConv,
|
||||
Conv::PreserveMost => llvm::PreserveMost,
|
||||
Conv::PreserveAll => llvm::PreserveAll,
|
||||
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
|
||||
Conv::AvrInterrupt => llvm::AvrInterrupt,
|
||||
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
|
||||
Conv::ArmAapcs => llvm::ArmAapcsCallConv,
|
||||
|
|
|
|||
|
|
@ -909,6 +909,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
ifn!("llvm.is.constant.isize", fn(t_isize) -> i1);
|
||||
ifn!("llvm.is.constant.f32", fn(t_f32) -> i1);
|
||||
ifn!("llvm.is.constant.f64", fn(t_f64) -> i1);
|
||||
ifn!("llvm.is.constant.ptr", fn(ptr) -> i1);
|
||||
|
||||
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
|
||||
ifn!("llvm.eh.typeid.for", fn(ptr) -> t_i32);
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
|
|||
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_> {
|
||||
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
|
||||
let diag: DiagnosticBuilder<'_, G> = self.0.into_diagnostic(dcx, level);
|
||||
let (message, _) = diag.messages().first().expect("`LlvmError` with no message");
|
||||
let (message, _) = diag.messages.first().expect("`LlvmError` with no message");
|
||||
let message = dcx.eagerly_translate_to_string(message.clone(), diag.args());
|
||||
|
||||
DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config)
|
||||
|
|
|
|||
|
|
@ -119,10 +119,18 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
sym::likely => {
|
||||
self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)])
|
||||
}
|
||||
sym::is_val_statically_known => self.call_intrinsic(
|
||||
&format!("llvm.is.constant.{:?}", args[0].layout.immediate_llvm_type(self.cx)),
|
||||
&[args[0].immediate()],
|
||||
),
|
||||
sym::is_val_statically_known => {
|
||||
let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx);
|
||||
match self.type_kind(intrinsic_type) {
|
||||
TypeKind::Pointer | TypeKind::Integer | TypeKind::Float | TypeKind::Double => {
|
||||
self.call_intrinsic(
|
||||
&format!("llvm.is.constant.{:?}", intrinsic_type),
|
||||
&[args[0].immediate()],
|
||||
)
|
||||
}
|
||||
_ => self.const_bool(false),
|
||||
}
|
||||
}
|
||||
sym::unlikely => self
|
||||
.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
|
||||
kw::Try => {
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ pub enum CallConv {
|
|||
X86_Intr = 83,
|
||||
AvrNonBlockingInterrupt = 84,
|
||||
AvrInterrupt = 85,
|
||||
AmdGpuKernel = 91,
|
||||
}
|
||||
|
||||
/// LLVMRustLinkage
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet};
|
|||
|
||||
use crate::errors::ErrorCreatingRemarkDir;
|
||||
use std::any::Any;
|
||||
use std::borrow::Cow;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
|
|
@ -1812,12 +1811,12 @@ impl Translate for SharedEmitter {
|
|||
|
||||
impl Emitter for SharedEmitter {
|
||||
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
|
||||
let args: FxHashMap<Cow<'_, str>, DiagnosticArgValue> =
|
||||
let args: FxHashMap<DiagnosticArgName, DiagnosticArgValue> =
|
||||
diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect();
|
||||
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
|
||||
msgs: diag.messages.clone(),
|
||||
args: args.clone(),
|
||||
code: diag.code.clone(),
|
||||
code: diag.code,
|
||||
lvl: diag.level(),
|
||||
})));
|
||||
for child in &diag.children {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use std::mem;
|
||||
|
||||
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg};
|
||||
use rustc_errors::{
|
||||
DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg,
|
||||
};
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_middle::mir::AssertKind;
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
|
|
@ -32,10 +34,7 @@ impl MachineStopType for ConstEvalErrKind {
|
|||
AssertFailure(x) => x.diagnostic_message(),
|
||||
}
|
||||
}
|
||||
fn add_args(
|
||||
self: Box<Self>,
|
||||
adder: &mut dyn FnMut(std::borrow::Cow<'static, str>, DiagnosticArgValue),
|
||||
) {
|
||||
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) {
|
||||
use ConstEvalErrKind::*;
|
||||
match *self {
|
||||
ConstAccessesStatic | ModifiedGlobal => {}
|
||||
|
|
@ -50,9 +49,7 @@ impl MachineStopType for ConstEvalErrKind {
|
|||
}
|
||||
}
|
||||
|
||||
// The errors become `MachineStop` with plain strings when being raised.
|
||||
// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
|
||||
// handle these.
|
||||
/// The errors become [`InterpError::MachineStop`] when being raised.
|
||||
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
|
||||
fn into(self) -> InterpErrorInfo<'tcx> {
|
||||
err_machine_stop!(self).into()
|
||||
|
|
|
|||
|
|
@ -373,7 +373,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) {
|
||||
// This is okay if they have the same metadata type.
|
||||
let meta_ty = |ty: Ty<'tcx>| {
|
||||
let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, |ty| ty);
|
||||
// Even if `ty` is normalized, the search for the unsized tail will project
|
||||
// to fields, which can yield non-normalized types. So we need to provide a
|
||||
// normalization function.
|
||||
let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty);
|
||||
let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, normalize);
|
||||
assert!(
|
||||
!only_if_sized,
|
||||
"there should be no more 'maybe has that metadata' types during interpretation"
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl
|
|||
Printer { f }
|
||||
}
|
||||
|
||||
// See comments in src/librustc_middle/lib.rs
|
||||
// See comments in compiler/rustc_middle/src/tests.rs
|
||||
#[doc(hidden)]
|
||||
pub fn __noop_fix_for_27438() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
An unnecessary type or const parameter was given in a type alias.
|
||||
An unnecessary type parameter was given in a type alias.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0091
|
||||
type Foo<T> = u32; // error: type parameter `T` is unused
|
||||
type Foo<T> = u32; // error: type parameter `T` is never used
|
||||
// or:
|
||||
type Foo<A,B> = Box<A>; // error: type parameter `B` is unused
|
||||
type Foo<A, B> = Box<A>; // error: type parameter `B` is never used
|
||||
```
|
||||
|
||||
Please check you didn't write too many parameters. Example:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ extern "C" {
|
|||
```
|
||||
|
||||
A list of available external lang items is available in
|
||||
`src/librustc_middle/middle/weak_lang_items.rs`. Example:
|
||||
`compiler/rustc_hir/src/weak_lang_items.rs`. Example:
|
||||
|
||||
```
|
||||
#![feature(lang_items)]
|
||||
|
|
|
|||
|
|
@ -33,7 +33,10 @@ pub type DiagnosticArgName = Cow<'static, str>;
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum DiagnosticArgValue {
|
||||
Str(Cow<'static, str>),
|
||||
Number(i128),
|
||||
// This gets converted to a `FluentNumber`, which is an `f64`. An `i32`
|
||||
// safely fits in an `f64`. Any integers bigger than that will be converted
|
||||
// to strings in `into_diagnostic_arg` and stored using the `Str` variant.
|
||||
Number(i32),
|
||||
StrListSepByAnd(Vec<Cow<'static, str>>),
|
||||
}
|
||||
|
||||
|
|
@ -109,13 +112,11 @@ pub struct Diagnostic {
|
|||
/// `span` if there is one. Otherwise, it is `DUMMY_SP`.
|
||||
pub sort_span: Span,
|
||||
|
||||
/// If diagnostic is from Lint, custom hash function ignores children.
|
||||
/// Otherwise hash is based on the all the fields.
|
||||
pub is_lint: Option<IsLint>,
|
||||
|
||||
/// With `-Ztrack_diagnostics` enabled,
|
||||
/// we print where in rustc this error was emitted.
|
||||
pub emitted_at: DiagnosticLocation,
|
||||
pub(crate) emitted_at: DiagnosticLocation,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
|
|
@ -164,10 +165,10 @@ impl DiagnosticStyledString {
|
|||
DiagnosticStyledString(vec![])
|
||||
}
|
||||
pub fn push_normal<S: Into<String>>(&mut self, t: S) {
|
||||
self.0.push(StringPart::Normal(t.into()));
|
||||
self.0.push(StringPart::normal(t));
|
||||
}
|
||||
pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
|
||||
self.0.push(StringPart::Highlighted(t.into()));
|
||||
self.0.push(StringPart::highlighted(t));
|
||||
}
|
||||
pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
|
||||
if highlight {
|
||||
|
|
@ -177,35 +178,34 @@ impl DiagnosticStyledString {
|
|||
}
|
||||
}
|
||||
pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
|
||||
DiagnosticStyledString(vec![StringPart::Normal(t.into())])
|
||||
DiagnosticStyledString(vec![StringPart::normal(t)])
|
||||
}
|
||||
|
||||
pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
|
||||
DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
|
||||
DiagnosticStyledString(vec![StringPart::highlighted(t)])
|
||||
}
|
||||
|
||||
pub fn content(&self) -> String {
|
||||
self.0.iter().map(|x| x.content()).collect::<String>()
|
||||
self.0.iter().map(|x| x.content.as_str()).collect::<String>()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum StringPart {
|
||||
Normal(String),
|
||||
Highlighted(String),
|
||||
pub struct StringPart {
|
||||
content: String,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl StringPart {
|
||||
pub fn content(&self) -> &str {
|
||||
match self {
|
||||
&StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s,
|
||||
}
|
||||
pub fn normal<S: Into<String>>(content: S) -> StringPart {
|
||||
StringPart { content: content.into(), style: Style::NoStyle }
|
||||
}
|
||||
|
||||
pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
|
||||
StringPart { content: content.into(), style: Style::Highlight }
|
||||
}
|
||||
}
|
||||
|
||||
// Note: most of these methods are setters that return `&mut Self`. The small
|
||||
// number of simple getter functions all have `get_` prefixes to distinguish
|
||||
// them from the setters.
|
||||
impl Diagnostic {
|
||||
#[track_caller]
|
||||
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
|
||||
|
|
@ -391,19 +391,16 @@ impl Diagnostic {
|
|||
} else {
|
||||
(0, found_label.len() - expected_label.len())
|
||||
};
|
||||
let mut msg: Vec<_> =
|
||||
vec![(format!("{}{} `", " ".repeat(expected_padding), expected_label), Style::NoStyle)];
|
||||
msg.extend(expected.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
|
||||
}));
|
||||
msg.push((format!("`{expected_extra}\n"), Style::NoStyle));
|
||||
msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle));
|
||||
msg.extend(found.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
|
||||
}));
|
||||
msg.push((format!("`{found_extra}"), Style::NoStyle));
|
||||
let mut msg = vec![StringPart::normal(format!(
|
||||
"{}{} `",
|
||||
" ".repeat(expected_padding),
|
||||
expected_label
|
||||
))];
|
||||
msg.extend(expected.0.into_iter());
|
||||
msg.push(StringPart::normal(format!("`{expected_extra}\n")));
|
||||
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
|
||||
msg.extend(found.0.into_iter());
|
||||
msg.push(StringPart::normal(format!("`{found_extra}")));
|
||||
|
||||
// For now, just attach these as notes.
|
||||
self.highlighted_note(msg);
|
||||
|
|
@ -412,9 +409,9 @@ impl Diagnostic {
|
|||
|
||||
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
|
||||
self.highlighted_note(vec![
|
||||
(format!("`{name}` from trait: `"), Style::NoStyle),
|
||||
(signature, Style::Highlight),
|
||||
("`".to_string(), Style::NoStyle),
|
||||
StringPart::normal(format!("`{name}` from trait: `")),
|
||||
StringPart::highlighted(signature),
|
||||
StringPart::normal("`"),
|
||||
]);
|
||||
self
|
||||
}
|
||||
|
|
@ -426,10 +423,7 @@ impl Diagnostic {
|
|||
self
|
||||
}
|
||||
|
||||
fn highlighted_note<M: Into<SubdiagnosticMessage>>(
|
||||
&mut self,
|
||||
msg: Vec<(M, Style)>,
|
||||
) -> &mut Self {
|
||||
fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
|
||||
self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
|
||||
self
|
||||
}
|
||||
|
|
@ -498,7 +492,7 @@ impl Diagnostic {
|
|||
}
|
||||
|
||||
/// Add a help message attached to this diagnostic with a customizable highlighted message.
|
||||
pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
|
||||
pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
|
||||
self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
|
||||
self
|
||||
}
|
||||
|
|
@ -892,15 +886,6 @@ impl Diagnostic {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn clear_code(&mut self) -> &mut Self {
|
||||
self.code = None;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_code(&self) -> Option<ErrCode> {
|
||||
self.code
|
||||
}
|
||||
|
||||
pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
|
||||
self.messages[0] = (msg.into(), Style::NoStyle);
|
||||
self
|
||||
|
|
@ -915,7 +900,7 @@ impl Diagnostic {
|
|||
|
||||
pub fn arg(
|
||||
&mut self,
|
||||
name: impl Into<Cow<'static, str>>,
|
||||
name: impl Into<DiagnosticArgName>,
|
||||
arg: impl IntoDiagnosticArg,
|
||||
) -> &mut Self {
|
||||
self.args.insert(name.into(), arg.into_diagnostic_arg());
|
||||
|
|
@ -926,10 +911,6 @@ impl Diagnostic {
|
|||
self.args = args;
|
||||
}
|
||||
|
||||
pub fn messages(&self) -> &[(DiagnosticMessage, Style)] {
|
||||
&self.messages
|
||||
}
|
||||
|
||||
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
|
||||
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
|
||||
/// passes the user's string along).
|
||||
|
|
@ -960,15 +941,10 @@ impl Diagnostic {
|
|||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// public methods above.
|
||||
fn sub_with_highlights<M: Into<SubdiagnosticMessage>>(
|
||||
&mut self,
|
||||
level: Level,
|
||||
messages: Vec<(M, Style)>,
|
||||
span: MultiSpan,
|
||||
) {
|
||||
fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
|
||||
let messages = messages
|
||||
.into_iter()
|
||||
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1))
|
||||
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
|
||||
.collect();
|
||||
let sub = SubDiagnostic { level, messages, span };
|
||||
self.children.push(sub);
|
||||
|
|
@ -980,22 +956,24 @@ impl Diagnostic {
|
|||
) -> (
|
||||
&Level,
|
||||
&[(DiagnosticMessage, Style)],
|
||||
Vec<(&Cow<'static, str>, &DiagnosticArgValue)>,
|
||||
&Option<ErrCode>,
|
||||
&Option<IsLint>,
|
||||
&MultiSpan,
|
||||
&[SubDiagnostic],
|
||||
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||
Option<&[SubDiagnostic]>,
|
||||
Vec<(&DiagnosticArgName, &DiagnosticArgValue)>,
|
||||
&Option<IsLint>,
|
||||
) {
|
||||
(
|
||||
&self.level,
|
||||
&self.messages,
|
||||
self.args().collect(),
|
||||
&self.code,
|
||||
&self.is_lint,
|
||||
&self.span,
|
||||
&self.children,
|
||||
&self.suggestions,
|
||||
(if self.is_lint.is_some() { None } else { Some(&self.children) }),
|
||||
self.args().collect(),
|
||||
// omit self.sort_span
|
||||
&self.is_lint,
|
||||
// omit self.emitted_at
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,13 +255,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|||
/// Stashes diagnostic for possible later improvement in a different,
|
||||
/// later stage of the compiler. The diagnostic can be accessed with
|
||||
/// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
|
||||
pub fn stash(self, span: Span, key: StashKey) {
|
||||
self.dcx.stash_diagnostic(span, key, self.into_diagnostic());
|
||||
}
|
||||
|
||||
/// Converts the builder to a `Diagnostic` for later emission.
|
||||
pub fn into_diagnostic(mut self) -> Diagnostic {
|
||||
self.take_diag()
|
||||
pub fn stash(mut self, span: Span, key: StashKey) {
|
||||
self.dcx.stash_diagnostic(span, key, self.take_diag());
|
||||
}
|
||||
|
||||
/// Delay emission of this diagnostic as a bug.
|
||||
|
|
|
|||
|
|
@ -63,12 +63,8 @@ macro_rules! into_diagnostic_arg_for_number {
|
|||
$(
|
||||
impl IntoDiagnosticArg for $ty {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue {
|
||||
// HACK: `FluentNumber` the underline backing struct represent
|
||||
// numbers using a f64 which can't represent all the i128 numbers
|
||||
// So in order to be able to use fluent selectors and still
|
||||
// have all the numbers representable we only convert numbers
|
||||
// below a certain threshold.
|
||||
if let Ok(n) = TryInto::<i128>::try_into(self) && n >= -100 && n <= 100 {
|
||||
// Convert to a string if it won't fit into `Number`.
|
||||
if let Ok(n) = TryInto::<i32>::try_into(self) {
|
||||
DiagnosticArgValue::Number(n)
|
||||
} else {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ impl Emitter for HumanEmitter {
|
|||
/// failures of rustc, as witnessed e.g. in issue #89358.
|
||||
pub struct SilentEmitter {
|
||||
pub fatal_dcx: DiagCtxt,
|
||||
pub fatal_note: Option<String>,
|
||||
pub fatal_note: String,
|
||||
}
|
||||
|
||||
impl Translate for SilentEmitter {
|
||||
|
|
@ -576,13 +576,11 @@ impl Emitter for SilentEmitter {
|
|||
None
|
||||
}
|
||||
|
||||
fn emit_diagnostic(&mut self, d: &Diagnostic) {
|
||||
if d.level == Level::Fatal {
|
||||
let mut d = d.clone();
|
||||
if let Some(ref note) = self.fatal_note {
|
||||
d.note(note.clone());
|
||||
}
|
||||
self.fatal_dcx.emit_diagnostic(d);
|
||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||
if diag.level == Level::Fatal {
|
||||
let mut diag = diag.clone();
|
||||
diag.note(self.fatal_note.clone());
|
||||
self.fatal_dcx.emit_diagnostic(diag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ extern crate self as rustc_errors;
|
|||
pub use codes::*;
|
||||
pub use diagnostic::{
|
||||
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName,
|
||||
DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
|
||||
DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, StringPart, SubDiagnostic,
|
||||
};
|
||||
pub use diagnostic_builder::{
|
||||
BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic,
|
||||
|
|
@ -102,7 +102,6 @@ pub type PResult<'a, T> = Result<T, PErr<'a>>;
|
|||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.)
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
|
|
@ -646,7 +645,8 @@ impl DiagCtxt {
|
|||
}
|
||||
|
||||
// This is here to not allow mutation of flags;
|
||||
// as of this writing it's only used in tests in librustc_middle.
|
||||
// as of this writing it's used in Session::consider_optimizing and
|
||||
// in tests in rustc_interface.
|
||||
pub fn can_emit_warnings(&self) -> bool {
|
||||
self.inner.borrow_mut().flags.can_emit_warnings
|
||||
}
|
||||
|
|
@ -1039,10 +1039,6 @@ impl DiagCtxt {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
|
||||
std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics)
|
||||
}
|
||||
|
||||
pub fn abort_if_errors(&self) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.emit_stashed_diagnostics();
|
||||
|
|
@ -1150,8 +1146,12 @@ impl DiagCtxt {
|
|||
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
|
||||
}
|
||||
|
||||
pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) {
|
||||
self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
|
||||
pub fn emit_future_breakage_report(&self) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
|
||||
if !diags.is_empty() {
|
||||
inner.emitter.emit_future_breakage_report(diags);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_unused_externs(
|
||||
|
|
@ -1224,9 +1224,8 @@ impl DiagCtxtInner {
|
|||
/// Emit all stashed diagnostics.
|
||||
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
|
||||
let has_errors = self.has_errors();
|
||||
let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
|
||||
let mut reported = None;
|
||||
for diag in diags {
|
||||
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
|
||||
// Decrement the count tracking the stash; emitting will increment it.
|
||||
if diag.is_error() {
|
||||
if diag.is_lint.is_some() {
|
||||
|
|
@ -1254,7 +1253,7 @@ impl DiagCtxtInner {
|
|||
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
|
||||
// a stable one by the `LintLevelsBuilder`.
|
||||
if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() {
|
||||
self.unstable_expect_diagnostics.push(diagnostic.clone());
|
||||
self.unstable_expect_diagnostics.push(diagnostic);
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -1269,16 +1268,14 @@ impl DiagCtxtInner {
|
|||
DelayedBug(DelayedBugKind::Normal) => {
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
self.span_delayed_bugs
|
||||
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
|
||||
|
||||
.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
||||
#[allow(deprecated)]
|
||||
return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
|
||||
}
|
||||
DelayedBug(DelayedBugKind::GoodPath) => {
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
self.good_path_delayed_bugs
|
||||
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
|
||||
|
||||
.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
||||
return None;
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -1424,7 +1421,7 @@ impl DiagCtxtInner {
|
|||
&mut out,
|
||||
"delayed span bug: {}\n{}\n",
|
||||
bug.inner
|
||||
.messages()
|
||||
.messages
|
||||
.iter()
|
||||
.filter_map(|(msg, _)| msg.as_str())
|
||||
.collect::<String>(),
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ pub struct StyledString {
|
|||
pub style: Style,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum Style {
|
||||
MainHeaderMsg,
|
||||
HeaderMsg,
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
} else {
|
||||
ast::BoundConstness::Never
|
||||
},
|
||||
asyncness: ast::BoundAsyncness::Normal,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ declare_features! (
|
|||
// feature-group-start: removed features
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// Allows using the `amdgpu-kernel` ABI.
|
||||
(removed, abi_amdgpu_kernel, "CURRENT_RUSTC_VERSION", Some(51575), None),
|
||||
(removed, advanced_slice_patterns, "1.0.0", Some(62254),
|
||||
Some("merged into `#![feature(slice_patterns)]`")),
|
||||
(removed, allocator, "1.0.0", None, None),
|
||||
|
|
|
|||
|
|
@ -321,8 +321,6 @@ declare_features! (
|
|||
// feature-group-start: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// Allows using the `amdgpu-kernel` ABI.
|
||||
(unstable, abi_amdgpu_kernel, "1.29.0", Some(51575)),
|
||||
/// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
|
||||
(unstable, abi_avr_interrupt, "1.45.0", Some(69664)),
|
||||
/// Allows `extern "C-cmse-nonsecure-call" fn()`.
|
||||
|
|
@ -498,7 +496,7 @@ declare_features! (
|
|||
/// Allow anonymous constants from an inline `const` block
|
||||
(unstable, inline_const, "1.49.0", Some(76001)),
|
||||
/// Allow anonymous constants from an inline `const` block in pattern position
|
||||
(incomplete, inline_const_pat, "1.58.0", Some(76001)),
|
||||
(unstable, inline_const_pat, "1.58.0", Some(76001)),
|
||||
/// Allows using `pointer` and `reference` in intra-doc links
|
||||
(unstable, intra_doc_pointers, "1.51.0", Some(80896)),
|
||||
// Allows setting the threshold for the `large_assignments` lint.
|
||||
|
|
|
|||
|
|
@ -894,34 +894,23 @@ impl<'tcx> OwnerInfo<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||
pub enum MaybeOwner<T> {
|
||||
Owner(T),
|
||||
pub enum MaybeOwner<'tcx> {
|
||||
Owner(&'tcx OwnerInfo<'tcx>),
|
||||
NonOwner(HirId),
|
||||
/// Used as a placeholder for unused LocalDefId.
|
||||
Phantom,
|
||||
}
|
||||
|
||||
impl<T> MaybeOwner<T> {
|
||||
pub fn as_owner(self) -> Option<T> {
|
||||
impl<'tcx> MaybeOwner<'tcx> {
|
||||
pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> {
|
||||
match self {
|
||||
MaybeOwner::Owner(i) => Some(i),
|
||||
MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> MaybeOwner<U> {
|
||||
match self {
|
||||
MaybeOwner::Owner(i) => MaybeOwner::Owner(f(i)),
|
||||
MaybeOwner::NonOwner(hir_id) => MaybeOwner::NonOwner(hir_id),
|
||||
MaybeOwner::Phantom => MaybeOwner::Phantom,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
MaybeOwner::Owner(i) => i,
|
||||
MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => panic!("Not a HIR owner"),
|
||||
}
|
||||
pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> {
|
||||
self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -933,7 +922,7 @@ impl<T> MaybeOwner<T> {
|
|||
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
|
||||
#[derive(Debug)]
|
||||
pub struct Crate<'hir> {
|
||||
pub owners: IndexVec<LocalDefId, MaybeOwner<&'hir OwnerInfo<'hir>>>,
|
||||
pub owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
|
||||
// Only present when incr. comp. is enabled.
|
||||
pub opt_hir_hash: Option<Fingerprint>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -434,6 +434,17 @@ hir_analysis_unused_associated_type_bounds =
|
|||
.note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
|
||||
.suggestion = remove this bound
|
||||
|
||||
hir_analysis_unused_generic_parameter =
|
||||
{$param_def_kind} `{$param_name}` is never used
|
||||
.label = unused {$param_def_kind}
|
||||
.const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead
|
||||
hir_analysis_unused_generic_parameter_adt_help =
|
||||
consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}`
|
||||
hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
|
||||
consider removing `{$param_name}` or referring to it in a field
|
||||
hir_analysis_unused_generic_parameter_ty_alias_help =
|
||||
consider removing `{$param_name}` or referring to it in the body of the type alias
|
||||
|
||||
hir_analysis_value_of_associated_struct_already_specified =
|
||||
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
|
||||
.label = re-bound here
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
let tcx = self.tcx();
|
||||
let sized_def_id = tcx.lang_items().sized_trait();
|
||||
let mut seen_negative_sized_bound = false;
|
||||
let mut seen_positive_sized_bound = false;
|
||||
|
||||
// Try to find an unbound in bounds.
|
||||
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
|
||||
|
|
@ -45,6 +46,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
seen_negative_sized_bound = true;
|
||||
}
|
||||
}
|
||||
hir::TraitBoundModifier::None => {
|
||||
if let Some(sized_def_id) = sized_def_id
|
||||
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
|
||||
{
|
||||
seen_positive_sized_bound = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -82,11 +90,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
);
|
||||
}
|
||||
|
||||
if seen_sized_unbound || seen_negative_sized_bound {
|
||||
// There was in fact a `?Sized` or `!Sized` bound;
|
||||
if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound {
|
||||
// There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound;
|
||||
// we don't need to do anything.
|
||||
} else if sized_def_id.is_some() {
|
||||
// There was no `?Sized` or `!Sized` bound;
|
||||
// There was no `?Sized`, `!Sized` or explicit `Sized` bound;
|
||||
// add `Sized` if it's available.
|
||||
bounds.push_sized(tcx, self_ty, span);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
err.span_suggestion_verbose(
|
||||
assoc_name.span,
|
||||
fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
|
||||
suggested_name.to_string(),
|
||||
suggested_name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
|||
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
|
||||
use std::cell::LazyCell;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
|
||||
|
|
@ -520,9 +521,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
}
|
||||
}
|
||||
DefKind::TyAlias => {
|
||||
let pty_ty = tcx.type_of(def_id).instantiate_identity();
|
||||
let generics = tcx.generics_of(def_id);
|
||||
check_type_params_are_used(tcx, generics, pty_ty);
|
||||
check_type_alias_type_params_are_used(tcx, def_id);
|
||||
}
|
||||
DefKind::ForeignMod => {
|
||||
let it = tcx.hir().expect_item(def_id);
|
||||
|
|
@ -1269,28 +1268,51 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_type_params_are_used<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
generics: &ty::Generics,
|
||||
ty: Ty<'tcx>,
|
||||
) {
|
||||
debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
|
||||
|
||||
assert_eq!(generics.parent, None);
|
||||
fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
|
||||
if tcx.type_alias_is_lazy(def_id) {
|
||||
// Since we compute the variances for lazy type aliases and already reject bivariant
|
||||
// parameters as unused, we can and should skip this check for lazy type aliases.
|
||||
return;
|
||||
}
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
if generics.own_counts().types == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut params_used = BitSet::new_empty(generics.params.len());
|
||||
|
||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
if ty.references_error() {
|
||||
// If there is already another error, do not emit
|
||||
// an error for not using a type parameter.
|
||||
// If there is already another error, do not emit an error for not using a type parameter.
|
||||
assert!(tcx.dcx().has_errors().is_some());
|
||||
return;
|
||||
}
|
||||
|
||||
// Lazily calculated because it is only needed in case of an error.
|
||||
let bounded_params = LazyCell::new(|| {
|
||||
tcx.explicit_predicates_of(def_id)
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|(predicate, span)| {
|
||||
let bounded_ty = match predicate.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(pred) => pred.trait_ref.self_ty(),
|
||||
ty::ClauseKind::TypeOutlives(pred) => pred.0,
|
||||
_ => return None,
|
||||
};
|
||||
if let ty::Param(param) = bounded_ty.kind() {
|
||||
Some((param.index, span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
// FIXME: This assumes that elaborated `Sized` bounds come first (which does hold at the
|
||||
// time of writing). This is a bit fragile since we later use the span to detect elaborated
|
||||
// `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized`
|
||||
// since it would overwrite the span of the user-written bound. This could be fixed by
|
||||
// folding the spans with `Span::to` which requires a bit of effort I think.
|
||||
.collect::<FxHashMap<_, _>>()
|
||||
});
|
||||
|
||||
let mut params_used = BitSet::new_empty(generics.params.len());
|
||||
for leaf in ty.walk() {
|
||||
if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
|
||||
&& let ty::Param(param) = leaf_ty.kind()
|
||||
|
|
@ -1305,15 +1327,24 @@ pub(super) fn check_type_params_are_used<'tcx>(
|
|||
&& let ty::GenericParamDefKind::Type { .. } = param.kind
|
||||
{
|
||||
let span = tcx.def_span(param.def_id);
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
let param_name = Ident::new(param.name, span);
|
||||
|
||||
// The corresponding predicates are post-`Sized`-elaboration. Therefore we
|
||||
// * check for emptiness to detect lone user-written `?Sized` bounds
|
||||
// * compare the param span to the pred span to detect lone user-written `Sized` bounds
|
||||
let has_explicit_bounds = bounded_params.is_empty()
|
||||
|| (*bounded_params).get(¶m.index).is_some_and(|&&pred_sp| pred_sp != span);
|
||||
let const_param_help = (!has_explicit_bounds).then_some(());
|
||||
|
||||
let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
|
||||
span,
|
||||
E0091,
|
||||
"type parameter `{}` is unused",
|
||||
param.name,
|
||||
)
|
||||
.with_span_label(span, "unused type parameter")
|
||||
.emit();
|
||||
param_name,
|
||||
param_def_kind: tcx.def_descr(param.def_id),
|
||||
help: errors::UnusedGenericParameterHelp::TyAlias { param_name },
|
||||
const_param_help,
|
||||
});
|
||||
diag.code(E0091);
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -578,7 +578,7 @@ pub fn check_function_signature<'tcx>(
|
|||
fn_id: LocalDefId,
|
||||
) -> rustc_span::Span {
|
||||
let mut args = {
|
||||
let node = tcx.hir().expect_owner(fn_id);
|
||||
let node = tcx.expect_hir_owner_node(fn_id);
|
||||
let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
|
||||
decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use crate::autoderef::Autoderef;
|
||||
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
||||
use crate::errors;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
|
|
@ -21,7 +20,7 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgs};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
|
|
@ -188,7 +187,7 @@ where
|
|||
}
|
||||
|
||||
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
|
||||
let node = tcx.hir().owner(def_id);
|
||||
let node = tcx.hir_owner_node(def_id);
|
||||
let mut res = match node {
|
||||
hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
|
||||
hir::OwnerNode::Item(item) => check_item(tcx, item),
|
||||
|
|
@ -1869,7 +1868,7 @@ fn check_variances_for_type_defn<'tcx>(
|
|||
hir::ParamName::Error => {}
|
||||
_ => {
|
||||
let has_explicit_bounds = explicitly_bounded_params.contains(¶meter);
|
||||
report_bivariance(tcx, hir_param, has_explicit_bounds);
|
||||
report_bivariance(tcx, hir_param, has_explicit_bounds, item.kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1879,30 +1878,38 @@ fn report_bivariance(
|
|||
tcx: TyCtxt<'_>,
|
||||
param: &rustc_hir::GenericParam<'_>,
|
||||
has_explicit_bounds: bool,
|
||||
item_kind: ItemKind<'_>,
|
||||
) -> ErrorGuaranteed {
|
||||
let span = param.span;
|
||||
let param_name = param.name.ident().name;
|
||||
let mut err = error_392(tcx, span, param_name);
|
||||
let param_name = param.name.ident();
|
||||
|
||||
let suggested_marker_id = tcx.lang_items().phantom_data();
|
||||
// Help is available only in presence of lang items.
|
||||
let msg = if let Some(def_id) = suggested_marker_id {
|
||||
format!(
|
||||
"consider removing `{}`, referring to it in a field, or using a marker such as `{}`",
|
||||
param_name,
|
||||
tcx.def_path_str(def_id),
|
||||
)
|
||||
} else {
|
||||
format!("consider removing `{param_name}` or referring to it in a field")
|
||||
let help = match item_kind {
|
||||
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
|
||||
if let Some(def_id) = tcx.lang_items().phantom_data() {
|
||||
errors::UnusedGenericParameterHelp::Adt {
|
||||
param_name,
|
||||
phantom_data: tcx.def_path_str(def_id),
|
||||
}
|
||||
} else {
|
||||
errors::UnusedGenericParameterHelp::AdtNoPhantomData { param_name }
|
||||
}
|
||||
}
|
||||
ItemKind::TyAlias(..) => errors::UnusedGenericParameterHelp::TyAlias { param_name },
|
||||
item_kind => bug!("report_bivariance: unexpected item kind: {item_kind:?}"),
|
||||
};
|
||||
err.help(msg);
|
||||
|
||||
if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
|
||||
err.help(format!(
|
||||
"if you intended `{param_name}` to be a const parameter, use `const {param_name}: usize` instead"
|
||||
));
|
||||
}
|
||||
err.emit()
|
||||
let const_param_help =
|
||||
matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds)
|
||||
.then_some(());
|
||||
|
||||
let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
|
||||
span: param.span,
|
||||
param_name,
|
||||
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
|
||||
help,
|
||||
const_param_help,
|
||||
});
|
||||
diag.code(E0392);
|
||||
diag.emit()
|
||||
}
|
||||
|
||||
impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
||||
|
|
@ -1967,11 +1974,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error
|
|||
res
|
||||
}
|
||||
|
||||
fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> {
|
||||
struct_span_code_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used")
|
||||
.with_span_label(span, "unused parameter")
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { check_mod_type_wf, check_well_formed, ..*providers };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
|
|||
map: &mut named_variable_map,
|
||||
scope: &Scope::Root { opt_parent_item: None },
|
||||
};
|
||||
match tcx.hir().owner(local_def_id) {
|
||||
match tcx.hir_owner_node(local_def_id) {
|
||||
hir::OwnerNode::Item(item) => visitor.visit_item(item),
|
||||
hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
|
||||
hir::OwnerNode::TraitItem(item) => {
|
||||
|
|
|
|||
|
|
@ -590,7 +590,6 @@ fn infer_placeholder_type<'a>(
|
|||
|
||||
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
|
||||
// We are typeck and have the real type, so remove that and suggest the actual type.
|
||||
// FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
|
||||
if let Ok(suggestions) = &mut err.suggestions {
|
||||
suggestions.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1511,3 +1511,27 @@ pub struct NotSupportedDelegation<'a> {
|
|||
#[label]
|
||||
pub callee_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_unused_generic_parameter)]
|
||||
pub(crate) struct UnusedGenericParameter {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub param_name: Ident,
|
||||
pub param_def_kind: &'static str,
|
||||
#[subdiagnostic]
|
||||
pub help: UnusedGenericParameterHelp,
|
||||
#[help(hir_analysis_const_param_help)]
|
||||
pub const_param_help: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum UnusedGenericParameterHelp {
|
||||
#[help(hir_analysis_unused_generic_parameter_adt_help)]
|
||||
Adt { param_name: Ident, phantom_data: String },
|
||||
#[help(hir_analysis_unused_generic_parameter_adt_no_phantom_data_help)]
|
||||
AdtNoPhantomData { param_name: Ident },
|
||||
#[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
|
||||
TyAlias { param_name: Ident },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1000,7 +1000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.span_suggestion_verbose(
|
||||
lhs.span.shrink_to_hi(),
|
||||
"you might have meant to write a semicolon here",
|
||||
";".to_string(),
|
||||
";",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -261,6 +261,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expr.kind
|
||||
&& let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
|
||||
&& self.can_coerce(recv_ty, expected)
|
||||
&& let name = method.name.as_str()
|
||||
&& (name.starts_with("to_") || name.starts_with("as_") || name == "into")
|
||||
{
|
||||
let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) {
|
||||
expr.span.with_lo(recv_span.hi())
|
||||
|
|
|
|||
|
|
@ -1116,9 +1116,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_name.span,
|
||||
format!(
|
||||
"you might have meant to use `{}`",
|
||||
inherent_method.name.as_str()
|
||||
inherent_method.name
|
||||
),
|
||||
inherent_method.name.as_str(),
|
||||
inherent_method.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
break 'outer;
|
||||
|
|
@ -2019,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
diag.span_suggestion_verbose(
|
||||
sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
|
||||
"you may have meant to call an instance method",
|
||||
".".to_string(),
|
||||
".",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if (lhs, rhs).references_error() {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
if self.tcx.sess.teach(err.get_code().unwrap()) {
|
||||
if self.tcx.sess.teach(err.code.unwrap()) {
|
||||
err.note(
|
||||
"In a match expression, only numbers and characters can be matched \
|
||||
against a range. This is because the compiler checks that the range \
|
||||
|
|
@ -847,7 +847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
type_str
|
||||
);
|
||||
err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
|
||||
if self.tcx.sess.teach(err.get_code().unwrap()) {
|
||||
if self.tcx.sess.teach(err.code.unwrap()) {
|
||||
err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
|
||||
}
|
||||
return Err(err.emit());
|
||||
|
|
@ -1669,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if tcx.sess.teach(err.get_code().unwrap()) {
|
||||
if tcx.sess.teach(err.code.unwrap()) {
|
||||
err.note(
|
||||
"This error indicates that a struct pattern attempted to \
|
||||
extract a nonexistent field from a struct. Struct fields \
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ impl<'tcx> IfThisChanged<'tcx> {
|
|||
None => DepNode::from_def_path_hash(
|
||||
self.tcx,
|
||||
def_path_hash,
|
||||
dep_kinds::hir_owner_nodes,
|
||||
dep_kinds::opt_hir_owner_nodes,
|
||||
),
|
||||
Some(n) => {
|
||||
match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ const BASE_FN: &[&str] = &[
|
|||
|
||||
/// DepNodes for Hir, which is pretty much everything
|
||||
const BASE_HIR: &[&str] = &[
|
||||
// hir_owner_nodes should be computed for all nodes
|
||||
label_strs::hir_owner_nodes,
|
||||
// opt_hir_owner_nodes should be computed for all nodes
|
||||
label_strs::opt_hir_owner_nodes,
|
||||
];
|
||||
|
||||
/// `impl` implementation of struct/trait
|
||||
|
|
|
|||
|
|
@ -2555,7 +2555,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
add_lt_suggs,
|
||||
new_lt: &new_lt,
|
||||
};
|
||||
match self.tcx.hir().expect_owner(lifetime_scope) {
|
||||
match self.tcx.expect_hir_owner_node(lifetime_scope) {
|
||||
hir::OwnerNode::Item(i) => visitor.visit_item(i),
|
||||
hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
|
||||
hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
if let hir::OwnerNode::Item(Item {
|
||||
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
|
||||
..
|
||||
}) = tcx.hir().owner(impl_did)
|
||||
}) = tcx.hir_owner_node(impl_did)
|
||||
{
|
||||
Some((impl_item.ident, self_ty))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
diag.help("type parameters must be constrained to match other types");
|
||||
if tcx.sess.teach(diag.get_code().unwrap()) {
|
||||
if tcx.sess.teach(diag.code.unwrap()) {
|
||||
diag.help(
|
||||
"given a type parameter `T` and a method `foo`:
|
||||
```
|
||||
|
|
@ -678,7 +678,7 @@ impl<T> Trait<T> for X {
|
|||
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
|
||||
);
|
||||
}
|
||||
if tcx.sess.teach(diag.get_code().unwrap()) {
|
||||
if tcx.sess.teach(diag.code.unwrap()) {
|
||||
diag.help(
|
||||
"given an associated type `T` and a method `foo`:
|
||||
```
|
||||
|
|
|
|||
|
|
@ -45,20 +45,19 @@ pub struct Compiler {
|
|||
pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
|
||||
cfgs.into_iter()
|
||||
.map(|s| {
|
||||
let sess = ParseSess::with_silent_emitter(Some(format!(
|
||||
let sess = ParseSess::with_silent_emitter(format!(
|
||||
"this error occurred on the command line: `--cfg={s}`"
|
||||
)));
|
||||
));
|
||||
let filename = FileName::cfg_spec_source_code(&s);
|
||||
|
||||
macro_rules! error {
|
||||
($reason: expr) => {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
dcx.struct_fatal(format!(
|
||||
dcx.fatal(format!(
|
||||
concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
|
||||
s
|
||||
))
|
||||
.emit();
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -108,20 +107,19 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
|
|||
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
|
||||
|
||||
for s in specs {
|
||||
let sess = ParseSess::with_silent_emitter(Some(format!(
|
||||
let sess = ParseSess::with_silent_emitter(format!(
|
||||
"this error occurred on the command line: `--check-cfg={s}`"
|
||||
)));
|
||||
));
|
||||
let filename = FileName::cfg_spec_source_code(&s);
|
||||
|
||||
macro_rules! error {
|
||||
($reason:expr) => {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
dcx.struct_fatal(format!(
|
||||
dcx.fatal(format!(
|
||||
concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
|
||||
s
|
||||
))
|
||||
.emit()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ use crate::nonstandard_style::{method_context, MethodLateContext};
|
|||
|
||||
use std::fmt::Write;
|
||||
|
||||
// hardwired lints from librustc_middle
|
||||
// hardwired lints from rustc_lint_defs
|
||||
pub use rustc_session::lint::builtin::*;
|
||||
|
||||
declare_lint! {
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe
|
|||
// Otherwise, we need to visit the attributes in source code order, so we fetch HIR and do
|
||||
// a standard visit.
|
||||
// FIXME(#102522) Just iterate on attrs once that iteration order matches HIR's.
|
||||
_ => match tcx.hir().owner(owner) {
|
||||
_ => match tcx.hir_owner_node(owner) {
|
||||
hir::OwnerNode::Item(item) => levels.visit_item(item),
|
||||
hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item),
|
||||
hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item),
|
||||
|
|
|
|||
|
|
@ -516,6 +516,10 @@ fn register_builtins(store: &mut LintStore) {
|
|||
"converted into hard error, see PR #118649 \
|
||||
<https://github.com/rust-lang/rust/pull/118649> for more information",
|
||||
);
|
||||
store.register_removed(
|
||||
"illegal_floating_point_literal_pattern",
|
||||
"no longer a warning, float patterns behave the same as `==`",
|
||||
);
|
||||
}
|
||||
|
||||
fn register_internals(store: &mut LintStore) {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ declare_lint_pass! {
|
|||
FUZZY_PROVENANCE_CASTS,
|
||||
HIDDEN_GLOB_REEXPORTS,
|
||||
ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
INCOMPLETE_INCLUDE,
|
||||
INDIRECT_STRUCTURAL_MATCH,
|
||||
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
|
||||
|
|
@ -1873,55 +1872,6 @@ declare_lint! {
|
|||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `illegal_floating_point_literal_pattern` lint detects
|
||||
/// floating-point literals used in patterns.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let x = 42.0;
|
||||
///
|
||||
/// match x {
|
||||
/// 5.0 => {}
|
||||
/// _ => {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Previous versions of the compiler accepted floating-point literals in
|
||||
/// patterns, but it was later determined this was a mistake. The
|
||||
/// semantics of comparing floating-point values may not be clear in a
|
||||
/// pattern when contrasted with "structural equality". Typically you can
|
||||
/// work around this by using a [match guard], such as:
|
||||
///
|
||||
/// ```rust
|
||||
/// # let x = 42.0;
|
||||
///
|
||||
/// match x {
|
||||
/// y if y == 5.0 => {}
|
||||
/// _ => {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This is a [future-incompatible] lint to transition this to a hard
|
||||
/// error in the future. See [issue #41620] for more details.
|
||||
///
|
||||
/// [issue #41620]: https://github.com/rust-lang/rust/issues/41620
|
||||
/// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
Warn,
|
||||
"floating-point literals cannot be used in patterns",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||
reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unstable_name_collisions` lint detects that you have used a name
|
||||
/// that the standard library plans to add in the future.
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ macro_rules! arena_types {
|
|||
|
||||
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
||||
// since we need to allocate this type on both the `rustc_hir` arena
|
||||
// (during lowering) and the `librustc_middle` arena (for decoding MIR)
|
||||
// (during lowering) and the `rustc_middle` arena (for decoding MIR)
|
||||
[decode] asm_template: rustc_ast::InlineAsmTemplatePiece,
|
||||
[decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>,
|
||||
[decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::ItemLocalId>,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
use rustc_errors::{codes::*, DiagnosticArgValue, DiagnosticMessage};
|
||||
use rustc_errors::{codes::*, DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
|
|
@ -95,14 +94,14 @@ pub(super) struct ConstNotUsedTraitAlias {
|
|||
|
||||
pub struct CustomSubdiagnostic<'a> {
|
||||
pub msg: fn() -> DiagnosticMessage,
|
||||
pub add_args: Box<dyn FnOnce(&mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue)) + 'a>,
|
||||
pub add_args: Box<dyn FnOnce(&mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) + 'a>,
|
||||
}
|
||||
|
||||
impl<'a> CustomSubdiagnostic<'a> {
|
||||
pub fn label(x: fn() -> DiagnosticMessage) -> Self {
|
||||
Self::label_and_then(x, |_| {})
|
||||
}
|
||||
pub fn label_and_then<F: FnOnce(&mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue)) + 'a>(
|
||||
pub fn label_and_then<F: FnOnce(&mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) + 'a>(
|
||||
msg: fn() -> DiagnosticMessage,
|
||||
f: F,
|
||||
) -> Self {
|
||||
|
|
|
|||
|
|
@ -107,9 +107,8 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current_id.local_id.index() != 0 {
|
||||
self.current_id.local_id = ItemLocalId::new(0);
|
||||
if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
|
||||
return Some((self.current_id.owner, node));
|
||||
}
|
||||
let node = self.map.tcx.hir_owner_node(self.current_id.owner);
|
||||
return Some((self.current_id.owner, node));
|
||||
}
|
||||
if self.current_id == CRATE_HIR_ID {
|
||||
return None;
|
||||
|
|
@ -125,22 +124,42 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
|
|||
self.current_id = HirId::make_owner(parent_id.def_id);
|
||||
|
||||
// If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
|
||||
if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
|
||||
return Some((self.current_id.owner, node));
|
||||
}
|
||||
let node = self.map.tcx.hir_owner_node(self.current_id.owner);
|
||||
return Some((self.current_id.owner, node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
#[inline]
|
||||
fn hir_owner(self, owner: OwnerId) -> Option<OwnerNode<'tcx>> {
|
||||
Some(self.hir_owner_nodes(owner).as_owner()?.node())
|
||||
fn expect_hir_owner_nodes(self, def_id: LocalDefId) -> &'tcx OwnerNodes<'tcx> {
|
||||
self.opt_hir_owner_nodes(def_id)
|
||||
.unwrap_or_else(|| span_bug!(self.def_span(def_id), "{def_id:?} is not an owner"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hir_owner_nodes(self, owner_id: OwnerId) -> &'tcx OwnerNodes<'tcx> {
|
||||
self.expect_hir_owner_nodes(owner_id.def_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn opt_hir_owner_node(self, def_id: LocalDefId) -> Option<OwnerNode<'tcx>> {
|
||||
self.opt_hir_owner_nodes(def_id).map(|nodes| nodes.node())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn expect_hir_owner_node(self, def_id: LocalDefId) -> OwnerNode<'tcx> {
|
||||
self.expect_hir_owner_nodes(def_id).node()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hir_owner_node(self, owner_id: OwnerId) -> OwnerNode<'tcx> {
|
||||
self.hir_owner_nodes(owner_id).node()
|
||||
}
|
||||
|
||||
/// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found.
|
||||
pub fn opt_hir_node(self, id: HirId) -> Option<Node<'tcx>> {
|
||||
let owner = self.hir_owner_nodes(id.owner).as_owner()?;
|
||||
let owner = self.hir_owner_nodes(id.owner);
|
||||
let node = owner.nodes[id.local_id].as_ref()?;
|
||||
Some(node.node)
|
||||
}
|
||||
|
|
@ -174,8 +193,8 @@ impl<'hir> Map<'hir> {
|
|||
|
||||
#[inline]
|
||||
pub fn root_module(self) -> &'hir Mod<'hir> {
|
||||
match self.tcx.hir_owner(CRATE_OWNER_ID) {
|
||||
Some(OwnerNode::Crate(item)) => item,
|
||||
match self.tcx.hir_owner_node(CRATE_OWNER_ID) {
|
||||
OwnerNode::Crate(item) => item,
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -213,7 +232,7 @@ impl<'hir> Map<'hir> {
|
|||
if id.local_id == ItemLocalId::from_u32(0) {
|
||||
Some(self.tcx.hir_owner_parent(id.owner))
|
||||
} else {
|
||||
let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?;
|
||||
let owner = self.tcx.hir_owner_nodes(id.owner);
|
||||
let node = owner.nodes[id.local_id].as_ref()?;
|
||||
let hir_id = HirId { owner: id.owner, local_id: node.parent };
|
||||
// HIR indexing should have checked that.
|
||||
|
|
@ -241,32 +260,27 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
|
||||
pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
|
||||
let node = self.tcx.hir_owner(OwnerId { def_id: id })?;
|
||||
node.generics()
|
||||
}
|
||||
|
||||
pub fn owner(self, id: OwnerId) -> OwnerNode<'hir> {
|
||||
self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id))
|
||||
self.tcx.opt_hir_owner_node(id)?.generics()
|
||||
}
|
||||
|
||||
pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
|
||||
self.tcx.hir_owner(id.owner_id).unwrap().expect_item()
|
||||
self.tcx.hir_owner_node(id.owner_id).expect_item()
|
||||
}
|
||||
|
||||
pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
|
||||
self.tcx.hir_owner(id.owner_id).unwrap().expect_trait_item()
|
||||
self.tcx.hir_owner_node(id.owner_id).expect_trait_item()
|
||||
}
|
||||
|
||||
pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
|
||||
self.tcx.hir_owner(id.owner_id).unwrap().expect_impl_item()
|
||||
self.tcx.hir_owner_node(id.owner_id).expect_impl_item()
|
||||
}
|
||||
|
||||
pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
|
||||
self.tcx.hir_owner(id.owner_id).unwrap().expect_foreign_item()
|
||||
self.tcx.hir_owner_node(id.owner_id).expect_foreign_item()
|
||||
}
|
||||
|
||||
pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
|
||||
self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
|
||||
self.tcx.hir_owner_nodes(id.hir_id.owner).bodies[&id.hir_id.local_id]
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
|
@ -436,9 +450,9 @@ impl<'hir> Map<'hir> {
|
|||
|
||||
pub fn get_module(self, module: LocalModDefId) -> (&'hir Mod<'hir>, Span, HirId) {
|
||||
let hir_id = HirId::make_owner(module.to_local_def_id());
|
||||
match self.tcx.hir_owner(hir_id.owner) {
|
||||
Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. })) => (m, span, hir_id),
|
||||
Some(OwnerNode::Crate(item)) => (item, item.spans.inner_span, hir_id),
|
||||
match self.tcx.hir_owner_node(hir_id.owner) {
|
||||
OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. }) => (m, span, hir_id),
|
||||
OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id),
|
||||
node => panic!("not a module: {node:?}"),
|
||||
}
|
||||
}
|
||||
|
|
@ -726,8 +740,8 @@ impl<'hir> Map<'hir> {
|
|||
|
||||
pub fn get_foreign_abi(self, hir_id: HirId) -> Abi {
|
||||
let parent = self.get_parent_item(hir_id);
|
||||
if let Some(node) = self.tcx.hir_owner(parent)
|
||||
&& let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node
|
||||
if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) =
|
||||
self.tcx.hir_owner_node(parent)
|
||||
{
|
||||
return *abi;
|
||||
}
|
||||
|
|
@ -737,38 +751,29 @@ impl<'hir> Map<'hir> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn expect_owner(self, def_id: LocalDefId) -> OwnerNode<'hir> {
|
||||
self.tcx
|
||||
.hir_owner(OwnerId { def_id })
|
||||
.unwrap_or_else(|| bug!("expected owner for {:?}", def_id))
|
||||
}
|
||||
|
||||
pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
|
||||
match self.tcx.hir_owner(OwnerId { def_id: id }) {
|
||||
Some(OwnerNode::Item(item)) => item,
|
||||
match self.tcx.expect_hir_owner_node(id) {
|
||||
OwnerNode::Item(item) => item,
|
||||
_ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
|
||||
match self.tcx.hir_owner(OwnerId { def_id: id }) {
|
||||
Some(OwnerNode::ImplItem(item)) => item,
|
||||
match self.tcx.expect_hir_owner_node(id) {
|
||||
OwnerNode::ImplItem(item) => item,
|
||||
_ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
|
||||
match self.tcx.hir_owner(OwnerId { def_id: id }) {
|
||||
Some(OwnerNode::TraitItem(item)) => item,
|
||||
match self.tcx.expect_hir_owner_node(id) {
|
||||
OwnerNode::TraitItem(item) => item,
|
||||
_ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fn_output(self, def_id: LocalDefId) -> Option<&'hir FnRetTy<'hir>> {
|
||||
match self.tcx.hir_owner(OwnerId { def_id }) {
|
||||
Some(node) => node.fn_decl().map(|fn_decl| &fn_decl.output),
|
||||
_ => None,
|
||||
}
|
||||
Some(&self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.output)
|
||||
}
|
||||
|
||||
pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> {
|
||||
|
|
@ -779,8 +784,8 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
|
||||
pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
|
||||
match self.tcx.hir_owner(id) {
|
||||
Some(OwnerNode::ForeignItem(item)) => item,
|
||||
match self.tcx.hir_owner_node(id) {
|
||||
OwnerNode::ForeignItem(item) => item,
|
||||
_ => {
|
||||
bug!(
|
||||
"expected foreign item, found {}",
|
||||
|
|
|
|||
|
|
@ -127,21 +127,15 @@ pub fn provide(providers: &mut Providers) {
|
|||
providers.hir_crate_items = map::hir_crate_items;
|
||||
providers.crate_hash = map::crate_hash;
|
||||
providers.hir_module_items = map::hir_module_items;
|
||||
providers.opt_local_def_id_to_hir_id = |tcx, id| {
|
||||
let owner = tcx.hir_crate(()).owners[id].map(|_| ());
|
||||
Some(match owner {
|
||||
MaybeOwner::Owner(_) => HirId::make_owner(id),
|
||||
MaybeOwner::Phantom => bug!("No HirId for {:?}", id),
|
||||
providers.opt_local_def_id_to_hir_id = |tcx, def_id| {
|
||||
Some(match tcx.hir_crate(()).owners[def_id] {
|
||||
MaybeOwner::Owner(_) => HirId::make_owner(def_id),
|
||||
MaybeOwner::NonOwner(hir_id) => hir_id,
|
||||
MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
|
||||
})
|
||||
};
|
||||
providers.hir_owner_nodes = |tcx, id| {
|
||||
if let Some(i) = tcx.hir_crate(()).owners.get(id.def_id) {
|
||||
i.map(|i| &i.nodes)
|
||||
} else {
|
||||
MaybeOwner::Phantom
|
||||
}
|
||||
};
|
||||
providers.opt_hir_owner_nodes =
|
||||
|tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
|
||||
providers.hir_owner_parent = |tcx, id| {
|
||||
// Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash.
|
||||
tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ use crate::mir::{ConstAlloc, ConstValue};
|
|||
use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
|
||||
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
|
||||
use rustc_errors::{
|
||||
DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg,
|
||||
};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_session::CtfeBacktrace;
|
||||
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
|
||||
|
|
@ -485,7 +487,7 @@ pub trait MachineStopType: Any + fmt::Debug + Send {
|
|||
fn diagnostic_message(&self) -> DiagnosticMessage;
|
||||
/// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to
|
||||
/// fluent for formatting the translated diagnostic message.
|
||||
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue));
|
||||
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue));
|
||||
}
|
||||
|
||||
impl dyn MachineStopType {
|
||||
|
|
|
|||
|
|
@ -418,8 +418,8 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
|
|||
|
||||
#[inline]
|
||||
pub fn to_float<F: Float>(self) -> InterpResult<'tcx, F> {
|
||||
// Going through `to_uint` to check size and truncation.
|
||||
Ok(F::from_bits(self.to_uint(Size::from_bits(F::BITS))?))
|
||||
// Going through `to_bits` to check size and truncation.
|
||||
Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex};
|
|||
use crate::ty::{GenericArg, GenericArgsRef};
|
||||
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
|
||||
use rustc_errors::{
|
||||
DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg,
|
||||
};
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
||||
use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind};
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ impl<O> AssertKind<O> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_args(self, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue))
|
||||
pub fn add_args(self, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue))
|
||||
where
|
||||
O: fmt::Debug,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -185,8 +185,8 @@ impl EraseType for Option<ty::EarlyBinder<Ty<'_>>> {
|
|||
type Result = [u8; size_of::<Option<ty::EarlyBinder<Ty<'static>>>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for rustc_hir::MaybeOwner<&'_ T> {
|
||||
type Result = [u8; size_of::<rustc_hir::MaybeOwner<&'static ()>>()];
|
||||
impl EraseType for rustc_hir::MaybeOwner<'_> {
|
||||
type Result = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
|
||||
}
|
||||
|
||||
impl<T: EraseType> EraseType for ty::EarlyBinder<T> {
|
||||
|
|
|
|||
|
|
@ -190,11 +190,11 @@ rustc_queries! {
|
|||
desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
/// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
|
||||
/// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner.
|
||||
///
|
||||
/// This can be conveniently accessed by methods on `tcx.hir()`.
|
||||
/// Avoid calling this query directly.
|
||||
query hir_owner_nodes(key: hir::OwnerId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
|
||||
query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
|
||||
desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::*;
|
||||
|
||||
// FIXME(#27438): right now the unit tests of librustc_middle don't refer to any actual
|
||||
// functions generated in librustc_data_structures (all
|
||||
// FIXME(#27438): right now the unit tests of rustc_middle don't refer to any actual
|
||||
// functions generated in rustc_data_structures (all
|
||||
// references are through generic functions), but statics are
|
||||
// referenced from time to time. Due to this bug we won't
|
||||
// actually correctly link in the statics unless we also
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::ConstKind as IrConstKind;
|
||||
use rustc_type_ir::{ConstTy, IntoKind, TypeFlags, WithCachedTypeInfo};
|
||||
|
||||
mod int;
|
||||
|
|
@ -19,7 +20,7 @@ use rustc_span::Span;
|
|||
use rustc_span::DUMMY_SP;
|
||||
pub use valtree::*;
|
||||
|
||||
use super::sty::ConstKind;
|
||||
pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
|
||||
|
||||
/// Use this rather than `ConstData`, whenever possible.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
||||
|
|
|
|||
|
|
@ -249,11 +249,6 @@ impl ScalarInt {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
|
||||
Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64)
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
|
||||
/// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
|
||||
/// `ScalarInt`s size in that case.
|
||||
|
|
@ -262,6 +257,51 @@ impl ScalarInt {
|
|||
self.to_bits(size)
|
||||
}
|
||||
|
||||
// Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
|
||||
// in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
|
||||
// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u8(self) -> Result<u8, Size> {
|
||||
self.try_to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u16(self) -> Result<u16, Size> {
|
||||
self.try_to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u32(self) -> Result<u32, Size> {
|
||||
self.try_to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u64(self) -> Result<u64, Size> {
|
||||
self.try_to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u128(self) -> Result<u128, Size> {
|
||||
self.try_to_uint(Size::from_bits(128))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
|
||||
self.try_to_uint(tcx.data_layout.pointer_size).map(|v| u64::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
// Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt`
|
||||
// in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size`
|
||||
// value of the `ScalarInt` in that case.
|
||||
|
|
@ -274,46 +314,6 @@ impl ScalarInt {
|
|||
}
|
||||
}
|
||||
|
||||
// Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
|
||||
// in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
|
||||
// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u8(self) -> Result<u8, Size> {
|
||||
self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u16(self) -> Result<u16, Size> {
|
||||
self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u32(self) -> Result<u32, Size> {
|
||||
self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u64(self) -> Result<u64, Size> {
|
||||
self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
|
||||
/// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
|
||||
/// that case.
|
||||
#[inline]
|
||||
pub fn try_to_u128(self) -> Result<u128, Size> {
|
||||
self.to_bits(Size::from_bits(128))
|
||||
}
|
||||
|
||||
/// Tries to convert the `ScalarInt` to a signed integer of the given size.
|
||||
/// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
|
||||
/// `ScalarInt`s size in that case.
|
||||
|
|
@ -357,6 +357,27 @@ impl ScalarInt {
|
|||
pub fn try_to_i128(self) -> Result<i128, Size> {
|
||||
self.try_to_int(Size::from_bits(128))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_isize(&self, tcx: TyCtxt<'_>) -> Result<i64, Size> {
|
||||
self.try_to_int(tcx.data_layout.pointer_size).map(|v| i64::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_float<F: Float>(self) -> Result<F, Size> {
|
||||
// Going through `to_uint` to check size and truncation.
|
||||
Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_f32(self) -> Result<Single, Size> {
|
||||
self.try_to_float()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_f64(self) -> Result<Double, Size> {
|
||||
self.try_to_float()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from {
|
||||
|
|
@ -399,11 +420,7 @@ impl TryFrom<ScalarInt> for bool {
|
|||
type Error = Size;
|
||||
#[inline]
|
||||
fn try_from(int: ScalarInt) -> Result<Self, Size> {
|
||||
int.to_bits(Size::from_bytes(1)).and_then(|u| match u {
|
||||
0 => Ok(false),
|
||||
1 => Ok(true),
|
||||
_ => Err(Size::from_bytes(1)),
|
||||
})
|
||||
int.try_to_bool()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1247,7 +1247,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) ->
|
|||
PtxKernel
|
||||
| Msp430Interrupt
|
||||
| X86Interrupt
|
||||
| AmdGpuKernel
|
||||
| EfiApi
|
||||
| AvrInterrupt
|
||||
| AvrNonBlockingInterrupt
|
||||
|
|
|
|||
|
|
@ -80,23 +80,34 @@ pub use self::closure::{
|
|||
CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList,
|
||||
RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, CAPTURE_STRUCT_LOCAL,
|
||||
};
|
||||
pub use self::consts::{Const, ConstData, ConstInt, Expr, ScalarInt, UnevaluatedConst, ValTree};
|
||||
pub use self::consts::{
|
||||
Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree,
|
||||
};
|
||||
pub use self::context::{
|
||||
tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed,
|
||||
};
|
||||
pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams};
|
||||
pub use self::list::List;
|
||||
pub use self::parameterized::ParameterizedOverTcx;
|
||||
pub use self::predicate::{
|
||||
Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection,
|
||||
ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
|
||||
PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
|
||||
PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
|
||||
PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
|
||||
RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitPredicate,
|
||||
TraitRef, TypeOutlivesPredicate,
|
||||
};
|
||||
pub use self::region::{
|
||||
BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region,
|
||||
RegionKind, RegionVid,
|
||||
};
|
||||
pub use self::rvalue_scopes::RvalueScopes;
|
||||
pub use self::sty::BoundRegionKind::*;
|
||||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind,
|
||||
BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind,
|
||||
CoroutineArgs, CoroutineArgsParts, EarlyParamRegion, ExistentialPredicate,
|
||||
ExistentialProjection, ExistentialTraitRef, FnSig, GenSig, InlineConstArgs,
|
||||
InlineConstArgsParts, LateParamRegion, ParamConst, ParamTy, PolyExistentialPredicate,
|
||||
PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyTraitRef, PredicateKind,
|
||||
Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
|
||||
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
|
||||
ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, FnSig, GenSig,
|
||||
InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut,
|
||||
UpvarArgs, VarianceDiagInfo,
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
|
|
@ -139,6 +150,8 @@ mod instance;
|
|||
mod list;
|
||||
mod opaque_types;
|
||||
mod parameterized;
|
||||
mod predicate;
|
||||
mod region;
|
||||
mod rvalue_scopes;
|
||||
mod structural_impls;
|
||||
#[allow(hidden_glob_reexports)]
|
||||
|
|
@ -491,165 +504,6 @@ impl EarlyParamRegion {
|
|||
}
|
||||
}
|
||||
|
||||
/// A statement that can be proven by a trait solver. This includes things that may
|
||||
/// show up in where clauses, such as trait predicates and projection predicates,
|
||||
/// and also things that are emitted as part of type checking such as `ObjectSafe`
|
||||
/// predicate which is emitted when a type is coerced to a trait object.
|
||||
///
|
||||
/// Use this rather than `PredicateKind`, whenever possible.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Predicate<'tcx>(
|
||||
Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
|
||||
);
|
||||
|
||||
impl<'tcx> Predicate<'tcx> {
|
||||
/// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
|
||||
#[inline]
|
||||
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
|
||||
self.0.internee
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flags(self) -> TypeFlags {
|
||||
self.0.flags
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn outer_exclusive_binder(self) -> DebruijnIndex {
|
||||
self.0.outer_exclusive_binder
|
||||
}
|
||||
|
||||
/// Flips the polarity of a Predicate.
|
||||
///
|
||||
/// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
|
||||
pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
|
||||
let kind = self
|
||||
.kind()
|
||||
.map_bound(|kind| match kind {
|
||||
PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
|
||||
trait_ref,
|
||||
polarity,
|
||||
})) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: polarity.flip()?,
|
||||
}))),
|
||||
|
||||
_ => None,
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
Some(tcx.mk_predicate(kind))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
|
||||
tcx.trait_is_coinductive(data.def_id())
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this projection can be soundly normalized.
|
||||
///
|
||||
/// Wf predicates must not be normalized, as normalization
|
||||
/// can remove required bounds which would cause us to
|
||||
/// unsoundly accept some programs. See #91068.
|
||||
#[inline]
|
||||
pub fn allow_normalization(self) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_)) => false,
|
||||
// `NormalizesTo` is only used in the new solver, so this shouldn't
|
||||
// matter. Normalizing `term` would be 'wrong' however, as it changes whether
|
||||
// `normalizes-to(<T as Trait>::Assoc, <T as Trait>::Assoc)` holds.
|
||||
PredicateKind::NormalizesTo(..) => false,
|
||||
PredicateKind::Clause(ClauseKind::Trait(_))
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::Projection(_))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::ObjectSafe(_)
|
||||
| PredicateKind::Subtype(_)
|
||||
| PredicateKind::Coerce(_)
|
||||
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(_))
|
||||
| PredicateKind::ConstEquate(_, _)
|
||||
| PredicateKind::Ambiguous => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue {
|
||||
rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl rustc_errors::IntoDiagnosticArg for Clause<'_> {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue {
|
||||
rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A subset of predicates which can be assumed by the trait solver. They show up in
|
||||
/// an item's where clauses, hence the name `Clause`, and may either be user-written
|
||||
/// (such as traits) or may be inserted during lowering.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>);
|
||||
|
||||
impl<'tcx> Clause<'tcx> {
|
||||
pub fn as_predicate(self) -> Predicate<'tcx> {
|
||||
Predicate(self.0)
|
||||
}
|
||||
|
||||
pub fn kind(self) -> Binder<'tcx, ClauseKind<'tcx>> {
|
||||
self.0.internee.map_bound(|kind| match kind {
|
||||
PredicateKind::Clause(clause) => clause,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_trait_clause(self) -> Option<Binder<'tcx, TraitPredicate<'tcx>>> {
|
||||
let clause = self.kind();
|
||||
if let ty::ClauseKind::Trait(trait_clause) = clause.skip_binder() {
|
||||
Some(clause.rebind(trait_clause))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_projection_clause(self) -> Option<Binder<'tcx, ProjectionPredicate<'tcx>>> {
|
||||
let clause = self.kind();
|
||||
if let ty::ClauseKind::Projection(projection_clause) = clause.skip_binder() {
|
||||
Some(clause.rebind(projection_clause))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_type_outlives_clause(self) -> Option<Binder<'tcx, TypeOutlivesPredicate<'tcx>>> {
|
||||
let clause = self.kind();
|
||||
if let ty::ClauseKind::TypeOutlives(o) = clause.skip_binder() {
|
||||
Some(clause.rebind(o))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_region_outlives_clause(self) -> Option<Binder<'tcx, RegionOutlivesPredicate<'tcx>>> {
|
||||
let clause = self.kind();
|
||||
if let ty::ClauseKind::RegionOutlives(o) = clause.skip_binder() {
|
||||
Some(clause.rebind(o))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
/// outlives of every item in the local crate. You should not use it
|
||||
/// directly, because to do so will make your pass dependent on the
|
||||
|
|
@ -664,189 +518,6 @@ pub struct CratePredicatesMap<'tcx> {
|
|||
pub predicates: DefIdMap<&'tcx [(Clause<'tcx>, Span)]>,
|
||||
}
|
||||
|
||||
impl<'tcx> Clause<'tcx> {
|
||||
/// Performs a substitution suitable for going from a
|
||||
/// poly-trait-ref to supertraits that must hold if that
|
||||
/// poly-trait-ref holds. This is slightly different from a normal
|
||||
/// substitution in terms of what happens with bound regions. See
|
||||
/// lengthy comment below for details.
|
||||
pub fn subst_supertrait(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
) -> Clause<'tcx> {
|
||||
// The interaction between HRTB and supertraits is not entirely
|
||||
// obvious. Let me walk you (and myself) through an example.
|
||||
//
|
||||
// Let's start with an easy case. Consider two traits:
|
||||
//
|
||||
// trait Foo<'a>: Bar<'a,'a> { }
|
||||
// trait Bar<'b,'c> { }
|
||||
//
|
||||
// Now, if we have a trait reference `for<'x> T: Foo<'x>`, then
|
||||
// we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we
|
||||
// knew that `Foo<'x>` (for any 'x) then we also know that
|
||||
// `Bar<'x,'x>` (for any 'x). This more-or-less falls out from
|
||||
// normal substitution.
|
||||
//
|
||||
// In terms of why this is sound, the idea is that whenever there
|
||||
// is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>`
|
||||
// holds. So if there is an impl of `T:Foo<'a>` that applies to
|
||||
// all `'a`, then we must know that `T:Bar<'a,'a>` holds for all
|
||||
// `'a`.
|
||||
//
|
||||
// Another example to be careful of is this:
|
||||
//
|
||||
// trait Foo1<'a>: for<'b> Bar1<'a,'b> { }
|
||||
// trait Bar1<'b,'c> { }
|
||||
//
|
||||
// Here, if we have `for<'x> T: Foo1<'x>`, then what do we know?
|
||||
// The answer is that we know `for<'x,'b> T: Bar1<'x,'b>`. The
|
||||
// reason is similar to the previous example: any impl of
|
||||
// `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`. So
|
||||
// basically we would want to collapse the bound lifetimes from
|
||||
// the input (`trait_ref`) and the supertraits.
|
||||
//
|
||||
// To achieve this in practice is fairly straightforward. Let's
|
||||
// consider the more complicated scenario:
|
||||
//
|
||||
// - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x`
|
||||
// has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`,
|
||||
// where both `'x` and `'b` would have a DB index of 1.
|
||||
// The substitution from the input trait-ref is therefore going to be
|
||||
// `'a => 'x` (where `'x` has a DB index of 1).
|
||||
// - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
|
||||
// early-bound parameter and `'b` is a late-bound parameter with a
|
||||
// DB index of 1.
|
||||
// - If we replace `'a` with `'x` from the input, it too will have
|
||||
// a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>`
|
||||
// just as we wanted.
|
||||
//
|
||||
// There is only one catch. If we just apply the substitution `'a
|
||||
// => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will
|
||||
// adjust the DB index because we substituting into a binder (it
|
||||
// tries to be so smart...) resulting in `for<'x> for<'b>
|
||||
// Bar1<'x,'b>` (we have no syntax for this, so use your
|
||||
// imagination). Basically the 'x will have DB index of 2 and 'b
|
||||
// will have DB index of 1. Not quite what we want. So we apply
|
||||
// the substitution to the *contents* of the trait reference,
|
||||
// rather than the trait reference itself (put another way, the
|
||||
// substitution code expects equal binding levels in the values
|
||||
// from the substitution and the value being substituted into, and
|
||||
// this trick achieves that).
|
||||
|
||||
// Working through the second example:
|
||||
// trait_ref: for<'x> T: Foo1<'^0.0>; args: [T, '^0.0]
|
||||
// predicate: for<'b> Self: Bar1<'a, '^0.0>; args: [Self, 'a, '^0.0]
|
||||
// We want to end up with:
|
||||
// for<'x, 'b> T: Bar1<'^0.0, '^0.1>
|
||||
// To do this:
|
||||
// 1) We must shift all bound vars in predicate by the length
|
||||
// of trait ref's bound vars. So, we would end up with predicate like
|
||||
// Self: Bar1<'a, '^0.1>
|
||||
// 2) We can then apply the trait args to this, ending up with
|
||||
// T: Bar1<'^0.0, '^0.1>
|
||||
// 3) Finally, to create the final bound vars, we concatenate the bound
|
||||
// vars of the trait ref with those of the predicate:
|
||||
// ['x, 'b]
|
||||
let bound_pred = self.kind();
|
||||
let pred_bound_vars = bound_pred.bound_vars();
|
||||
let trait_bound_vars = trait_ref.bound_vars();
|
||||
// 1) Self: Bar1<'a, '^0.0> -> Self: Bar1<'a, '^0.1>
|
||||
let shifted_pred =
|
||||
tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder());
|
||||
// 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1>
|
||||
let new = EarlyBinder::bind(shifted_pred).instantiate(tcx, trait_ref.skip_binder().args);
|
||||
// 3) ['x] + ['b] -> ['x, 'b]
|
||||
let bound_vars =
|
||||
tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars));
|
||||
|
||||
// FIXME: Is it really perf sensitive to use reuse_or_mk_predicate here?
|
||||
tcx.reuse_or_mk_predicate(
|
||||
self.as_predicate(),
|
||||
ty::Binder::bind_with_vars(PredicateKind::Clause(new), bound_vars),
|
||||
)
|
||||
.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct TraitPredicate<'tcx> {
|
||||
pub trait_ref: TraitRef<'tcx>,
|
||||
|
||||
/// If polarity is Positive: we are proving that the trait is implemented.
|
||||
///
|
||||
/// If polarity is Negative: we are proving that a negative impl of this trait
|
||||
/// exists. (Note that coherence also checks whether negative impls of supertraits
|
||||
/// exist via a series of predicates.)
|
||||
///
|
||||
/// If polarity is Reserved: that's a bug.
|
||||
pub polarity: ImplPolarity,
|
||||
}
|
||||
|
||||
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> TraitPredicate<'tcx> {
|
||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||
Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self }
|
||||
}
|
||||
|
||||
pub fn def_id(self) -> DefId {
|
||||
self.trait_ref.def_id
|
||||
}
|
||||
|
||||
pub fn self_ty(self) -> Ty<'tcx> {
|
||||
self.trait_ref.self_ty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PolyTraitPredicate<'tcx> {
|
||||
pub fn def_id(self) -> DefId {
|
||||
// Ok to skip binder since trait `DefId` does not care about regions.
|
||||
self.skip_binder().def_id()
|
||||
}
|
||||
|
||||
pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> {
|
||||
self.map_bound(|trait_ref| trait_ref.self_ty())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn polarity(self) -> ImplPolarity {
|
||||
self.skip_binder().polarity
|
||||
}
|
||||
}
|
||||
|
||||
/// `A: B`
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct OutlivesPredicate<A, B>(pub A, pub B);
|
||||
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
|
||||
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
|
||||
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
|
||||
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
|
||||
|
||||
/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
|
||||
/// whether the `a` type is the type that we should label as "expected" when
|
||||
/// presenting user diagnostics.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct SubtypePredicate<'tcx> {
|
||||
pub a_is_expected: bool,
|
||||
pub a: Ty<'tcx>,
|
||||
pub b: Ty<'tcx>,
|
||||
}
|
||||
pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
|
||||
|
||||
/// Encodes that we have to coerce *from* the `a` type to the `b` type.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct CoercePredicate<'tcx> {
|
||||
pub a: Ty<'tcx>,
|
||||
pub b: Ty<'tcx>,
|
||||
}
|
||||
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Term<'tcx> {
|
||||
ptr: NonNull<()>,
|
||||
|
|
@ -1048,351 +719,6 @@ impl From<ty::ConstVid> for TermVid {
|
|||
}
|
||||
}
|
||||
|
||||
/// This kind of predicate has no *direct* correspondent in the
|
||||
/// syntax, but it roughly corresponds to the syntactic forms:
|
||||
///
|
||||
/// 1. `T: TraitRef<..., Item = Type>`
|
||||
/// 2. `<T as TraitRef<...>>::Item == Type` (NYI)
|
||||
///
|
||||
/// In particular, form #1 is "desugared" to the combination of a
|
||||
/// normal trait predicate (`T: TraitRef<...>`) and one of these
|
||||
/// predicates. Form #2 is a broader form in that it also permits
|
||||
/// equality between arbitrary types. Processing an instance of
|
||||
/// Form #2 eventually yields one of these `ProjectionPredicate`
|
||||
/// instances to normalize the LHS.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct ProjectionPredicate<'tcx> {
|
||||
pub projection_ty: AliasTy<'tcx>,
|
||||
pub term: Term<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ProjectionPredicate<'tcx> {
|
||||
pub fn self_ty(self) -> Ty<'tcx> {
|
||||
self.projection_ty.self_ty()
|
||||
}
|
||||
|
||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ProjectionPredicate<'tcx> {
|
||||
Self { projection_ty: self.projection_ty.with_self_ty(tcx, self_ty), ..self }
|
||||
}
|
||||
|
||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
self.projection_ty.trait_def_id(tcx)
|
||||
}
|
||||
|
||||
pub fn def_id(self) -> DefId {
|
||||
self.projection_ty.def_id
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyProjectionPredicate<'tcx> {
|
||||
/// Returns the `DefId` of the trait of the associated item being projected.
|
||||
#[inline]
|
||||
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
self.skip_binder().projection_ty.trait_def_id(tcx)
|
||||
}
|
||||
|
||||
/// Get the [PolyTraitRef] required for this projection to be well formed.
|
||||
/// Note that for generic associated types the predicates of the associated
|
||||
/// type also need to be checked.
|
||||
#[inline]
|
||||
pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
|
||||
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
|
||||
// `self.0.trait_ref` is permitted to have escaping regions.
|
||||
// This is because here `self` has a `Binder` and so does our
|
||||
// return value, so we are preserving the number of binding
|
||||
// levels.
|
||||
self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
|
||||
}
|
||||
|
||||
pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
|
||||
self.map_bound(|predicate| predicate.term)
|
||||
}
|
||||
|
||||
/// The `DefId` of the `TraitItem` for the associated type.
|
||||
///
|
||||
/// Note that this is not the `DefId` of the `TraitRef` containing this
|
||||
/// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
|
||||
pub fn projection_def_id(&self) -> DefId {
|
||||
// Ok to skip binder since trait `DefId` does not care about regions.
|
||||
self.skip_binder().projection_ty.def_id
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be
|
||||
/// proven by actually normalizing `alias`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct NormalizesTo<'tcx> {
|
||||
pub alias: AliasTy<'tcx>,
|
||||
pub term: Term<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> NormalizesTo<'tcx> {
|
||||
pub fn self_ty(self) -> Ty<'tcx> {
|
||||
self.alias.self_ty()
|
||||
}
|
||||
|
||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> NormalizesTo<'tcx> {
|
||||
Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self }
|
||||
}
|
||||
|
||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
self.alias.trait_def_id(tcx)
|
||||
}
|
||||
|
||||
pub fn def_id(self) -> DefId {
|
||||
self.alias.def_id
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToPolyTraitRef<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
|
||||
self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToPredicate<'tcx, P = Predicate<'tcx>> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P;
|
||||
}
|
||||
|
||||
impl<'tcx, T> ToPredicate<'tcx, T> for T {
|
||||
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
ty::Binder::dummy(self).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
tcx.mk_predicate(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
self.as_predicate()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
ty::Binder::dummy(self).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> {
|
||||
TraitPredicate { trait_ref: self, polarity: ImplPolarity::Positive }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
p.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
|
||||
pred.to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
|
||||
pred.to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
|
||||
self.map_bound(|trait_ref| TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
p.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
p.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(self))).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
p.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
p.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for NormalizesTo<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
PredicateKind::NormalizesTo(self).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Predicate<'tcx> {
|
||||
pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
|
||||
let predicate = self.kind();
|
||||
match predicate.skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(ClauseKind::Projection(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(..))
|
||||
| PredicateKind::Clause(ClauseKind::WellFormed(..))
|
||||
| PredicateKind::ObjectSafe(..)
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
|
||||
| PredicateKind::ConstEquate(..)
|
||||
| PredicateKind::Ambiguous => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> {
|
||||
let predicate = self.kind();
|
||||
match predicate.skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(ClauseKind::Trait(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(..))
|
||||
| PredicateKind::Clause(ClauseKind::WellFormed(..))
|
||||
| PredicateKind::ObjectSafe(..)
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
|
||||
| PredicateKind::ConstEquate(..)
|
||||
| PredicateKind::Ambiguous => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`.
|
||||
pub fn as_clause(self) -> Option<Clause<'tcx>> {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(..) => Some(self.expect_clause()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert that the predicate is a clause.
|
||||
pub fn expect_clause(self) -> Clause<'tcx> {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(..) => Clause(self.0),
|
||||
_ => bug!("{self} is not a clause"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the bounds declared on a particular set of type
|
||||
/// parameters. Should eventually be generalized into a flag list of
|
||||
/// where-clauses. You can obtain an `InstantiatedPredicates` list from a
|
||||
|
|
|
|||
1062
compiler/rustc_middle/src/ty/predicate.rs
Normal file
1062
compiler/rustc_middle/src/ty/predicate.rs
Normal file
File diff suppressed because it is too large
Load diff
399
compiler/rustc_middle/src/ty/region.rs
Normal file
399
compiler/rustc_middle/src/ty/region.rs
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
use polonius_engine::Atom;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::Idx;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
||||
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::ty::{self, BoundVar, TyCtxt, TypeFlags};
|
||||
|
||||
pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
|
||||
|
||||
/// Use this rather than `RegionKind`, whenever possible.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
|
||||
|
||||
impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> {
|
||||
type Kind = RegionKind<'tcx>;
|
||||
|
||||
fn kind(self) -> RegionKind<'tcx> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Region<'tcx> {
|
||||
#[inline]
|
||||
pub fn new_early_param(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
early_bound_region: ty::EarlyParamRegion,
|
||||
) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::ReEarlyParam(early_bound_region))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_bound(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
bound_region: ty::BoundRegion,
|
||||
) -> Region<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
if let ty::BoundRegion { var, kind: ty::BrAnon } = bound_region
|
||||
&& let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize())
|
||||
&& let Some(re) = inner.get(var.as_usize()).copied()
|
||||
{
|
||||
re
|
||||
} else {
|
||||
tcx.intern_region(ty::ReBound(debruijn, bound_region))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_late_param(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
scope: DefId,
|
||||
bound_region: ty::BoundRegionKind,
|
||||
) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::ReLateParam(ty::LateParamRegion { scope, bound_region }))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
tcx.lifetimes
|
||||
.re_vars
|
||||
.get(v.as_usize())
|
||||
.copied()
|
||||
.unwrap_or_else(|| tcx.intern_region(ty::ReVar(v)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::RePlaceholder(placeholder))
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region.
|
||||
#[track_caller]
|
||||
pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::ReError(reported))
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it
|
||||
/// gets used.
|
||||
#[track_caller]
|
||||
pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> {
|
||||
Region::new_error_with_message(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
"RegionKind::ReError constructed but no error reported",
|
||||
)
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given
|
||||
/// `msg` to ensure it gets used.
|
||||
#[track_caller]
|
||||
pub fn new_error_with_message<S: Into<MultiSpan>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: S,
|
||||
msg: &'static str,
|
||||
) -> Region<'tcx> {
|
||||
let reported = tcx.dcx().span_delayed_bug(span, msg);
|
||||
Region::new_error(tcx, reported)
|
||||
}
|
||||
|
||||
/// Avoid this in favour of more specific `new_*` methods, where possible,
|
||||
/// to avoid the cost of the `match`.
|
||||
pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> {
|
||||
match kind {
|
||||
ty::ReEarlyParam(region) => Region::new_early_param(tcx, region),
|
||||
ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region),
|
||||
ty::ReLateParam(ty::LateParamRegion { scope, bound_region }) => {
|
||||
Region::new_late_param(tcx, scope, bound_region)
|
||||
}
|
||||
ty::ReStatic => tcx.lifetimes.re_static,
|
||||
ty::ReVar(vid) => Region::new_var(tcx, vid),
|
||||
ty::RePlaceholder(region) => Region::new_placeholder(tcx, region),
|
||||
ty::ReErased => tcx.lifetimes.re_erased,
|
||||
ty::ReError(reported) => Region::new_error(tcx, reported),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Region utilities
|
||||
impl<'tcx> Region<'tcx> {
|
||||
pub fn kind(self) -> RegionKind<'tcx> {
|
||||
*self.0.0
|
||||
}
|
||||
|
||||
pub fn get_name(self) -> Option<Symbol> {
|
||||
if self.has_name() {
|
||||
match *self {
|
||||
ty::ReEarlyParam(ebr) => Some(ebr.name),
|
||||
ty::ReBound(_, br) => br.kind.get_name(),
|
||||
ty::ReLateParam(fr) => fr.bound_region.get_name(),
|
||||
ty::ReStatic => Some(kw::StaticLifetime),
|
||||
ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name_or_anon(self) -> Symbol {
|
||||
match self.get_name() {
|
||||
Some(name) => name,
|
||||
None => sym::anon,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this region named by the user?
|
||||
pub fn has_name(self) -> bool {
|
||||
match *self {
|
||||
ty::ReEarlyParam(ebr) => ebr.has_name(),
|
||||
ty::ReBound(_, br) => br.kind.is_named(),
|
||||
ty::ReLateParam(fr) => fr.bound_region.is_named(),
|
||||
ty::ReStatic => true,
|
||||
ty::ReVar(..) => false,
|
||||
ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(),
|
||||
ty::ReErased => false,
|
||||
ty::ReError(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_error(self) -> bool {
|
||||
matches!(*self, ty::ReError(_))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_static(self) -> bool {
|
||||
matches!(*self, ty::ReStatic)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_erased(self) -> bool {
|
||||
matches!(*self, ty::ReErased)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_bound(self) -> bool {
|
||||
matches!(*self, ty::ReBound(..))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_placeholder(self) -> bool {
|
||||
matches!(*self, ty::RePlaceholder(..))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
|
||||
match *self {
|
||||
ty::ReBound(debruijn, _) => debruijn >= index,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_flags(self) -> TypeFlags {
|
||||
let mut flags = TypeFlags::empty();
|
||||
|
||||
match *self {
|
||||
ty::ReVar(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_INFER;
|
||||
}
|
||||
ty::RePlaceholder(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
|
||||
}
|
||||
ty::ReEarlyParam(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_PARAM;
|
||||
}
|
||||
ty::ReLateParam { .. } => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
}
|
||||
ty::ReStatic => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
ty::ReBound(..) => {
|
||||
flags = flags | TypeFlags::HAS_RE_BOUND;
|
||||
}
|
||||
ty::ReErased => {
|
||||
flags = flags | TypeFlags::HAS_RE_ERASED;
|
||||
}
|
||||
ty::ReError(_) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
}
|
||||
|
||||
debug!("type_flags({:?}) = {:?}", self, flags);
|
||||
|
||||
flags
|
||||
}
|
||||
|
||||
/// Given an early-bound or free region, returns the `DefId` where it was bound.
|
||||
/// For example, consider the regions in this snippet of code:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// impl<'a> Foo {
|
||||
/// // ^^ -- early bound, declared on an impl
|
||||
///
|
||||
/// fn bar<'b, 'c>(x: &self, y: &'b u32, z: &'c u64) where 'static: 'c
|
||||
/// // ^^ ^^ ^ anonymous, late-bound
|
||||
/// // | early-bound, appears in where-clauses
|
||||
/// // late-bound, appears only in fn args
|
||||
/// {..}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here, `free_region_binding_scope('a)` would return the `DefId`
|
||||
/// of the impl, and for all the other highlighted regions, it
|
||||
/// would return the `DefId` of the function. In other cases (not shown), this
|
||||
/// function might return the `DefId` of a closure.
|
||||
pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
|
||||
match *self {
|
||||
ty::ReEarlyParam(br) => tcx.parent(br.def_id),
|
||||
ty::ReLateParam(fr) => fr.scope,
|
||||
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
/// True for free regions other than `'static`.
|
||||
pub fn is_param(self) -> bool {
|
||||
matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_))
|
||||
}
|
||||
|
||||
/// True for free region in the current context.
|
||||
///
|
||||
/// This is the case for `'static` and param regions.
|
||||
pub fn is_free(self) -> bool {
|
||||
match *self {
|
||||
ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true,
|
||||
ty::ReVar(..)
|
||||
| ty::RePlaceholder(..)
|
||||
| ty::ReBound(..)
|
||||
| ty::ReErased
|
||||
| ty::ReError(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_var(self) -> bool {
|
||||
matches!(self.kind(), ty::ReVar(_))
|
||||
}
|
||||
|
||||
pub fn as_var(self) -> RegionVid {
|
||||
match self.kind() {
|
||||
ty::ReVar(vid) => vid,
|
||||
_ => bug!("expected region {:?} to be of kind ReVar", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Deref for Region<'tcx> {
|
||||
type Target = RegionKind<'tcx>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &RegionKind<'tcx> {
|
||||
self.0.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)]
|
||||
#[derive(HashStable)]
|
||||
pub struct EarlyParamRegion {
|
||||
pub def_id: DefId,
|
||||
pub index: u32,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for EarlyParamRegion {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A **region** (lifetime) **v**ariable **ID**.
|
||||
#[derive(HashStable)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[debug_format = "'?{}"]
|
||||
pub struct RegionVid {}
|
||||
}
|
||||
|
||||
impl Atom for RegionVid {
|
||||
fn index(self) -> usize {
|
||||
Idx::index(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
|
||||
#[derive(HashStable)]
|
||||
/// The parameter representation of late-bound function parameters, "some region
|
||||
/// at least as big as the scope `fr.scope`".
|
||||
pub struct LateParamRegion {
|
||||
pub scope: DefId,
|
||||
pub bound_region: BoundRegionKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
|
||||
#[derive(HashStable)]
|
||||
pub enum BoundRegionKind {
|
||||
/// An anonymous region parameter for a given fn (&T)
|
||||
BrAnon,
|
||||
|
||||
/// Named region parameters for functions (a in &'a T)
|
||||
///
|
||||
/// The `DefId` is needed to distinguish free regions in
|
||||
/// the event of shadowing.
|
||||
BrNamed(DefId, Symbol),
|
||||
|
||||
/// Anonymous region for the implicit env pointer parameter
|
||||
/// to a closure
|
||||
BrEnv,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)]
|
||||
#[derive(HashStable)]
|
||||
pub struct BoundRegion {
|
||||
pub var: BoundVar,
|
||||
pub kind: BoundRegionKind,
|
||||
}
|
||||
|
||||
impl BoundRegionKind {
|
||||
pub fn is_named(&self) -> bool {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(_, name) => {
|
||||
name != kw::UnderscoreLifetime && name != kw::Empty
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Option<Symbol> {
|
||||
if self.is_named() {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(_, name) => return Some(name),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> Option<DefId> {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(id, _) => return Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,42 +6,32 @@ use crate::infer::canonical::Canonical;
|
|||
use crate::ty::visit::ValidateBoundVars;
|
||||
use crate::ty::InferTy::*;
|
||||
use crate::ty::{
|
||||
self, AdtDef, Discr, IntoKind, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor,
|
||||
self, AdtDef, BoundRegionKind, Discr, Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
|
||||
use crate::ty::{List, ParamEnv};
|
||||
use hir::def::DefKind;
|
||||
use polonius_engine::Atom;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{
|
||||
DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_index::Idx;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
|
||||
use rustc_target::spec::abi::{self, Abi};
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::ops::{ControlFlow, Deref, Range};
|
||||
use ty::util::IntTypeExt;
|
||||
|
||||
use rustc_type_ir::BoundVar;
|
||||
use rustc_type_ir::ClauseKind as IrClauseKind;
|
||||
use rustc_type_ir::CollectAndApply;
|
||||
use rustc_type_ir::ConstKind as IrConstKind;
|
||||
use rustc_type_ir::DebugWithInfcx;
|
||||
use rustc_type_ir::DynKind;
|
||||
use rustc_type_ir::PredicateKind as IrPredicateKind;
|
||||
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||
use rustc_type_ir::TyKind as IrTyKind;
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::TypeAndMut as IrTypeAndMut;
|
||||
|
|
@ -51,74 +41,8 @@ use super::GenericParamDefKind;
|
|||
// Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
|
||||
#[rustc_diagnostic_item = "TyKind"]
|
||||
pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
|
||||
pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
|
||||
pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
|
||||
pub type PredicateKind<'tcx> = IrPredicateKind<TyCtxt<'tcx>>;
|
||||
pub type ClauseKind<'tcx> = IrClauseKind<TyCtxt<'tcx>>;
|
||||
pub type TypeAndMut<'tcx> = IrTypeAndMut<TyCtxt<'tcx>>;
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
|
||||
#[derive(HashStable)]
|
||||
/// The parameter representation of late-bound function parameters, "some region
|
||||
/// at least as big as the scope `fr.scope`".
|
||||
pub struct LateParamRegion {
|
||||
pub scope: DefId,
|
||||
pub bound_region: BoundRegionKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
|
||||
#[derive(HashStable)]
|
||||
pub enum BoundRegionKind {
|
||||
/// An anonymous region parameter for a given fn (&T)
|
||||
BrAnon,
|
||||
|
||||
/// Named region parameters for functions (a in &'a T)
|
||||
///
|
||||
/// The `DefId` is needed to distinguish free regions in
|
||||
/// the event of shadowing.
|
||||
BrNamed(DefId, Symbol),
|
||||
|
||||
/// Anonymous region for the implicit env pointer parameter
|
||||
/// to a closure
|
||||
BrEnv,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)]
|
||||
#[derive(HashStable)]
|
||||
pub struct BoundRegion {
|
||||
pub var: BoundVar,
|
||||
pub kind: BoundRegionKind,
|
||||
}
|
||||
|
||||
impl BoundRegionKind {
|
||||
pub fn is_named(&self) -> bool {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(_, name) => {
|
||||
name != kw::UnderscoreLifetime && name != kw::Empty
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Option<Symbol> {
|
||||
if self.is_named() {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(_, name) => return Some(name),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> Option<DefId> {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(id, _) => return Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Article {
|
||||
fn article(&self) -> &'static str;
|
||||
}
|
||||
|
|
@ -645,290 +569,6 @@ impl<'tcx> InlineConstArgs<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub enum ExistentialPredicate<'tcx> {
|
||||
/// E.g., `Iterator`.
|
||||
Trait(ExistentialTraitRef<'tcx>),
|
||||
/// E.g., `Iterator::Item = T`.
|
||||
Projection(ExistentialProjection<'tcx>),
|
||||
/// E.g., `Send`.
|
||||
AutoTrait(DefId),
|
||||
}
|
||||
|
||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> {
|
||||
fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
||||
this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut core::fmt::Formatter<'_>,
|
||||
) -> core::fmt::Result {
|
||||
fmt::Debug::fmt(&this.data, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ExistentialPredicate<'tcx> {
|
||||
/// Compares via an ordering that will not change if modules are reordered or other changes are
|
||||
/// made to the tree. In particular, this ordering is preserved across incremental compilations.
|
||||
pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering {
|
||||
use self::ExistentialPredicate::*;
|
||||
match (*self, *other) {
|
||||
(Trait(_), Trait(_)) => Ordering::Equal,
|
||||
(Projection(ref a), Projection(ref b)) => {
|
||||
tcx.def_path_hash(a.def_id).cmp(&tcx.def_path_hash(b.def_id))
|
||||
}
|
||||
(AutoTrait(ref a), AutoTrait(ref b)) => {
|
||||
tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b))
|
||||
}
|
||||
(Trait(_), _) => Ordering::Less,
|
||||
(Projection(_), Trait(_)) => Ordering::Greater,
|
||||
(Projection(_), _) => Ordering::Less,
|
||||
(AutoTrait(_), _) => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyExistentialPredicate<'tcx> = Binder<'tcx, ExistentialPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyExistentialPredicate<'tcx> {
|
||||
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
||||
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
|
||||
/// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
|
||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> {
|
||||
use crate::ty::ToPredicate;
|
||||
match self.skip_binder() {
|
||||
ExistentialPredicate::Trait(tr) => {
|
||||
self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx)
|
||||
}
|
||||
ExistentialPredicate::Projection(p) => {
|
||||
self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
|
||||
}
|
||||
ExistentialPredicate::AutoTrait(did) => {
|
||||
let generics = tcx.generics_of(did);
|
||||
let trait_ref = if generics.params.len() == 1 {
|
||||
ty::TraitRef::new(tcx, did, [self_ty])
|
||||
} else {
|
||||
// If this is an ill-formed auto trait, then synthesize
|
||||
// new error args for the missing generics.
|
||||
let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
|
||||
ty::TraitRef::new(tcx, did, err_args)
|
||||
};
|
||||
self.rebind(trait_ref).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
/// Returns the "principal `DefId`" of this set of existential predicates.
|
||||
///
|
||||
/// A Rust trait object type consists (in addition to a lifetime bound)
|
||||
/// of a set of trait bounds, which are separated into any number
|
||||
/// of auto-trait bounds, and at most one non-auto-trait bound. The
|
||||
/// non-auto-trait bound is called the "principal" of the trait
|
||||
/// object.
|
||||
///
|
||||
/// Only the principal can have methods or type parameters (because
|
||||
/// auto traits can have neither of them). This is important, because
|
||||
/// it means the auto traits can be treated as an unordered set (methods
|
||||
/// would force an order for the vtable, while relating traits with
|
||||
/// type parameters without knowing the order to relate them in is
|
||||
/// a rather non-trivial task).
|
||||
///
|
||||
/// For example, in the trait object `dyn fmt::Debug + Sync`, the
|
||||
/// principal bound is `Some(fmt::Debug)`, while the auto-trait bounds
|
||||
/// are the set `{Sync}`.
|
||||
///
|
||||
/// It is also possible to have a "trivial" trait object that
|
||||
/// consists only of auto traits, with no principal - for example,
|
||||
/// `dyn Send + Sync`. In that case, the set of auto-trait bounds
|
||||
/// is `{Send, Sync}`, while there is no principal. These trait objects
|
||||
/// have a "trivial" vtable consisting of just the size, alignment,
|
||||
/// and destructor.
|
||||
pub fn principal(&self) -> Option<ty::Binder<'tcx, ExistentialTraitRef<'tcx>>> {
|
||||
self[0]
|
||||
.map_bound(|this| match this {
|
||||
ExistentialPredicate::Trait(tr) => Some(tr),
|
||||
_ => None,
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
pub fn principal_def_id(&self) -> Option<DefId> {
|
||||
self.principal().map(|trait_ref| trait_ref.skip_binder().def_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn projection_bounds<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> + 'a {
|
||||
self.iter().filter_map(|predicate| {
|
||||
predicate
|
||||
.map_bound(|pred| match pred {
|
||||
ExistentialPredicate::Projection(projection) => Some(projection),
|
||||
_ => None,
|
||||
})
|
||||
.transpose()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + Captures<'tcx> + 'a {
|
||||
self.iter().filter_map(|predicate| match predicate.skip_binder() {
|
||||
ExistentialPredicate::AutoTrait(did) => Some(did),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A complete reference to a trait. These take numerous guises in syntax,
|
||||
/// but perhaps the most recognizable form is in a where-clause:
|
||||
/// ```ignore (illustrative)
|
||||
/// T: Foo<U>
|
||||
/// ```
|
||||
/// This would be represented by a trait-reference where the `DefId` is the
|
||||
/// `DefId` for the trait `Foo` and the args define `T` as parameter 0,
|
||||
/// and `U` as parameter 1.
|
||||
///
|
||||
/// Trait references also appear in object types like `Foo<U>`, but in
|
||||
/// that case the `Self` parameter is absent from the substitutions.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct TraitRef<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
/// This field exists to prevent the creation of `TraitRef` without
|
||||
/// calling [`TraitRef::new`].
|
||||
pub(super) _use_trait_ref_new_instead: (),
|
||||
}
|
||||
|
||||
impl<'tcx> TraitRef<'tcx> {
|
||||
pub fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
|
||||
) -> Self {
|
||||
let args = tcx.check_and_mk_args(trait_def_id, args);
|
||||
Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () }
|
||||
}
|
||||
|
||||
pub fn from_lang_item(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_lang_item: LangItem,
|
||||
span: Span,
|
||||
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
|
||||
) -> Self {
|
||||
let trait_def_id = tcx.require_lang_item(trait_lang_item, Some(span));
|
||||
Self::new(tcx, trait_def_id, args)
|
||||
}
|
||||
|
||||
pub fn from_method(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_id: DefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> ty::TraitRef<'tcx> {
|
||||
let defs = tcx.generics_of(trait_id);
|
||||
ty::TraitRef::new(tcx, trait_id, tcx.mk_args(&args[..defs.params.len()]))
|
||||
}
|
||||
|
||||
/// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
|
||||
/// are the parameters defined on trait.
|
||||
pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> {
|
||||
ty::TraitRef::new(tcx, def_id, GenericArgs::identity_for_item(tcx, def_id))
|
||||
}
|
||||
|
||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
self.def_id,
|
||||
[self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||
self.args.type_at(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyTraitRef<'tcx> = Binder<'tcx, TraitRef<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyTraitRef<'tcx> {
|
||||
pub fn self_ty(&self) -> Binder<'tcx, Ty<'tcx>> {
|
||||
self.map_bound_ref(|tr| tr.self_ty())
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> IntoDiagnosticArg for TraitRef<'tcx> {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
|
||||
/// An existential reference to a trait, where `Self` is erased.
|
||||
/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
|
||||
/// ```ignore (illustrative)
|
||||
/// exists T. T: Trait<'a, 'b, X, Y>
|
||||
/// ```
|
||||
/// The substitutions don't include the erased `Self`, only trait
|
||||
/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct ExistentialTraitRef<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ExistentialTraitRef<'tcx> {
|
||||
pub fn erase_self_ty(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> ty::ExistentialTraitRef<'tcx> {
|
||||
// Assert there is a Self.
|
||||
trait_ref.args.type_at(0);
|
||||
|
||||
ty::ExistentialTraitRef {
|
||||
def_id: trait_ref.def_id,
|
||||
args: tcx.mk_args(&trait_ref.args[1..]),
|
||||
}
|
||||
}
|
||||
|
||||
/// Object types don't have a self type specified. Therefore, when
|
||||
/// we convert the principal trait-ref into a normal trait-ref,
|
||||
/// you must give *some* self type. A common choice is `mk_err()`
|
||||
/// or some placeholder type.
|
||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> {
|
||||
// otherwise the escaping vars would be captured by the binder
|
||||
// debug_assert!(!self_ty.has_escaping_bound_vars());
|
||||
|
||||
ty::TraitRef::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> IntoDiagnosticArg for ExistentialTraitRef<'tcx> {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyExistentialTraitRef<'tcx> = Binder<'tcx, ExistentialTraitRef<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyExistentialTraitRef<'tcx> {
|
||||
pub fn def_id(&self) -> DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
|
||||
/// Object types don't have a self type specified. Therefore, when
|
||||
/// we convert the principal trait-ref into a normal trait-ref,
|
||||
/// you must give *some* self type. A common choice is `mk_err()`
|
||||
/// or some placeholder type.
|
||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTraitRef<'tcx> {
|
||||
self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable)]
|
||||
pub enum BoundVariableKind {
|
||||
|
|
@ -1452,154 +1092,6 @@ impl ParamConst {
|
|||
}
|
||||
}
|
||||
|
||||
/// Use this rather than `RegionKind`, whenever possible.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
|
||||
|
||||
impl<'tcx> IntoKind for Region<'tcx> {
|
||||
type Kind = RegionKind<'tcx>;
|
||||
|
||||
fn kind(self) -> RegionKind<'tcx> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Region<'tcx> {
|
||||
#[inline]
|
||||
pub fn new_early_param(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
early_bound_region: ty::EarlyParamRegion,
|
||||
) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::ReEarlyParam(early_bound_region))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_bound(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
bound_region: ty::BoundRegion,
|
||||
) -> Region<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
if let ty::BoundRegion { var, kind: ty::BrAnon } = bound_region
|
||||
&& let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize())
|
||||
&& let Some(re) = inner.get(var.as_usize()).copied()
|
||||
{
|
||||
re
|
||||
} else {
|
||||
tcx.intern_region(ty::ReBound(debruijn, bound_region))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_late_param(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
scope: DefId,
|
||||
bound_region: ty::BoundRegionKind,
|
||||
) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::ReLateParam(ty::LateParamRegion { scope, bound_region }))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
tcx.lifetimes
|
||||
.re_vars
|
||||
.get(v.as_usize())
|
||||
.copied()
|
||||
.unwrap_or_else(|| tcx.intern_region(ty::ReVar(v)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::RePlaceholder(placeholder))
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region.
|
||||
#[track_caller]
|
||||
pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> {
|
||||
tcx.intern_region(ty::ReError(reported))
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it
|
||||
/// gets used.
|
||||
#[track_caller]
|
||||
pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> {
|
||||
Region::new_error_with_message(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
"RegionKind::ReError constructed but no error reported",
|
||||
)
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given
|
||||
/// `msg` to ensure it gets used.
|
||||
#[track_caller]
|
||||
pub fn new_error_with_message<S: Into<MultiSpan>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: S,
|
||||
msg: &'static str,
|
||||
) -> Region<'tcx> {
|
||||
let reported = tcx.dcx().span_delayed_bug(span, msg);
|
||||
Region::new_error(tcx, reported)
|
||||
}
|
||||
|
||||
/// Avoid this in favour of more specific `new_*` methods, where possible,
|
||||
/// to avoid the cost of the `match`.
|
||||
pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> {
|
||||
match kind {
|
||||
ty::ReEarlyParam(region) => Region::new_early_param(tcx, region),
|
||||
ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region),
|
||||
ty::ReLateParam(ty::LateParamRegion { scope, bound_region }) => {
|
||||
Region::new_late_param(tcx, scope, bound_region)
|
||||
}
|
||||
ty::ReStatic => tcx.lifetimes.re_static,
|
||||
ty::ReVar(vid) => Region::new_var(tcx, vid),
|
||||
ty::RePlaceholder(region) => Region::new_placeholder(tcx, region),
|
||||
ty::ReErased => tcx.lifetimes.re_erased,
|
||||
ty::ReError(reported) => Region::new_error(tcx, reported),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Deref for Region<'tcx> {
|
||||
type Target = RegionKind<'tcx>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &RegionKind<'tcx> {
|
||||
self.0.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)]
|
||||
#[derive(HashStable)]
|
||||
pub struct EarlyParamRegion {
|
||||
pub def_id: DefId,
|
||||
pub index: u32,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
impl fmt::Debug for EarlyParamRegion {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A **region** (lifetime) **v**ariable **ID**.
|
||||
#[derive(HashStable)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[debug_format = "'?{}"]
|
||||
pub struct RegionVid {}
|
||||
}
|
||||
|
||||
impl Atom for RegionVid {
|
||||
fn index(self) -> usize {
|
||||
Idx::index(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable)]
|
||||
pub struct BoundTy {
|
||||
|
|
@ -1620,251 +1112,6 @@ impl From<BoundVar> for BoundTy {
|
|||
}
|
||||
}
|
||||
|
||||
/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct ExistentialProjection<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
pub term: Term<'tcx>,
|
||||
}
|
||||
|
||||
pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
|
||||
|
||||
impl<'tcx> ExistentialProjection<'tcx> {
|
||||
/// Extracts the underlying existential trait reference from this projection.
|
||||
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
||||
/// then this function would return an `exists T. T: Iterator` existential trait
|
||||
/// reference.
|
||||
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
|
||||
let def_id = tcx.parent(self.def_id);
|
||||
let subst_count = tcx.generics_of(def_id).count() - 1;
|
||||
let args = tcx.mk_args(&self.args[..subst_count]);
|
||||
ty::ExistentialTraitRef { def_id, args }
|
||||
}
|
||||
|
||||
pub fn with_self_ty(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
) -> ty::ProjectionPredicate<'tcx> {
|
||||
// otherwise the escaping regions would be captured by the binders
|
||||
debug_assert!(!self_ty.has_escaping_bound_vars());
|
||||
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: AliasTy::new(
|
||||
tcx,
|
||||
self.def_id,
|
||||
[self_ty.into()].into_iter().chain(self.args),
|
||||
),
|
||||
term: self.term,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn erase_self_ty(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
projection_predicate: ty::ProjectionPredicate<'tcx>,
|
||||
) -> Self {
|
||||
// Assert there is a Self.
|
||||
projection_predicate.projection_ty.args.type_at(0);
|
||||
|
||||
Self {
|
||||
def_id: projection_predicate.projection_ty.def_id,
|
||||
args: tcx.mk_args(&projection_predicate.projection_ty.args[1..]),
|
||||
term: projection_predicate.term,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PolyExistentialProjection<'tcx> {
|
||||
pub fn with_self_ty(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
) -> ty::PolyProjectionPredicate<'tcx> {
|
||||
self.map_bound(|p| p.with_self_ty(tcx, self_ty))
|
||||
}
|
||||
|
||||
pub fn item_def_id(&self) -> DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
}
|
||||
|
||||
/// Region utilities
|
||||
impl<'tcx> Region<'tcx> {
|
||||
pub fn kind(self) -> RegionKind<'tcx> {
|
||||
*self.0.0
|
||||
}
|
||||
|
||||
pub fn get_name(self) -> Option<Symbol> {
|
||||
if self.has_name() {
|
||||
match *self {
|
||||
ty::ReEarlyParam(ebr) => Some(ebr.name),
|
||||
ty::ReBound(_, br) => br.kind.get_name(),
|
||||
ty::ReLateParam(fr) => fr.bound_region.get_name(),
|
||||
ty::ReStatic => Some(kw::StaticLifetime),
|
||||
ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name_or_anon(self) -> Symbol {
|
||||
match self.get_name() {
|
||||
Some(name) => name,
|
||||
None => sym::anon,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this region named by the user?
|
||||
pub fn has_name(self) -> bool {
|
||||
match *self {
|
||||
ty::ReEarlyParam(ebr) => ebr.has_name(),
|
||||
ty::ReBound(_, br) => br.kind.is_named(),
|
||||
ty::ReLateParam(fr) => fr.bound_region.is_named(),
|
||||
ty::ReStatic => true,
|
||||
ty::ReVar(..) => false,
|
||||
ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(),
|
||||
ty::ReErased => false,
|
||||
ty::ReError(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_error(self) -> bool {
|
||||
matches!(*self, ty::ReError(_))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_static(self) -> bool {
|
||||
matches!(*self, ty::ReStatic)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_erased(self) -> bool {
|
||||
matches!(*self, ty::ReErased)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_bound(self) -> bool {
|
||||
matches!(*self, ty::ReBound(..))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_placeholder(self) -> bool {
|
||||
matches!(*self, ty::RePlaceholder(..))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
|
||||
match *self {
|
||||
ty::ReBound(debruijn, _) => debruijn >= index,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_flags(self) -> TypeFlags {
|
||||
let mut flags = TypeFlags::empty();
|
||||
|
||||
match *self {
|
||||
ty::ReVar(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_INFER;
|
||||
}
|
||||
ty::RePlaceholder(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
|
||||
}
|
||||
ty::ReEarlyParam(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_PARAM;
|
||||
}
|
||||
ty::ReLateParam { .. } => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
|
||||
}
|
||||
ty::ReStatic => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
ty::ReBound(..) => {
|
||||
flags = flags | TypeFlags::HAS_RE_BOUND;
|
||||
}
|
||||
ty::ReErased => {
|
||||
flags = flags | TypeFlags::HAS_RE_ERASED;
|
||||
}
|
||||
ty::ReError(_) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
}
|
||||
|
||||
debug!("type_flags({:?}) = {:?}", self, flags);
|
||||
|
||||
flags
|
||||
}
|
||||
|
||||
/// Given an early-bound or free region, returns the `DefId` where it was bound.
|
||||
/// For example, consider the regions in this snippet of code:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// impl<'a> Foo {
|
||||
/// // ^^ -- early bound, declared on an impl
|
||||
///
|
||||
/// fn bar<'b, 'c>(x: &self, y: &'b u32, z: &'c u64) where 'static: 'c
|
||||
/// // ^^ ^^ ^ anonymous, late-bound
|
||||
/// // | early-bound, appears in where-clauses
|
||||
/// // late-bound, appears only in fn args
|
||||
/// {..}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here, `free_region_binding_scope('a)` would return the `DefId`
|
||||
/// of the impl, and for all the other highlighted regions, it
|
||||
/// would return the `DefId` of the function. In other cases (not shown), this
|
||||
/// function might return the `DefId` of a closure.
|
||||
pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
|
||||
match *self {
|
||||
ty::ReEarlyParam(br) => tcx.parent(br.def_id),
|
||||
ty::ReLateParam(fr) => fr.scope,
|
||||
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
/// True for free regions other than `'static`.
|
||||
pub fn is_param(self) -> bool {
|
||||
matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_))
|
||||
}
|
||||
|
||||
/// True for free region in the current context.
|
||||
///
|
||||
/// This is the case for `'static` and param regions.
|
||||
pub fn is_free(self) -> bool {
|
||||
match *self {
|
||||
ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true,
|
||||
ty::ReVar(..)
|
||||
| ty::RePlaceholder(..)
|
||||
| ty::ReBound(..)
|
||||
| ty::ReErased
|
||||
| ty::ReError(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_var(self) -> bool {
|
||||
matches!(self.kind(), ty::ReVar(_))
|
||||
}
|
||||
|
||||
pub fn as_var(self) -> RegionVid {
|
||||
match self.kind() {
|
||||
ty::ReVar(vid) => vid,
|
||||
_ => bug!("expected region {:?} to be of kind ReVar", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructors for `Ty`
|
||||
impl<'tcx> Ty<'tcx> {
|
||||
// Avoid this in favour of more specific `new_*` methods, where possible.
|
||||
|
|
@ -2116,7 +1363,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
#[inline]
|
||||
pub fn new_dynamic(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
obj: &'tcx List<PolyExistentialPredicate<'tcx>>,
|
||||
obj: &'tcx List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
reg: ty::Region<'tcx>,
|
||||
repr: DynKind,
|
||||
) -> Ty<'tcx> {
|
||||
|
|
@ -3017,7 +2264,7 @@ mod size_asserts {
|
|||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(RegionKind<'_>, 24);
|
||||
static_assert_size!(TyKind<'_>, 32);
|
||||
static_assert_size!(ty::RegionKind<'_>, 24);
|
||||
static_assert_size!(ty::TyKind<'_>, 32);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,8 +107,6 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
|||
.note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
|
||||
.label = use of extern static
|
||||
|
||||
mir_build_float_pattern = floating-point types cannot be used in patterns
|
||||
|
||||
mir_build_indirect_structural_match =
|
||||
to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]`
|
||||
|
||||
|
|
@ -232,6 +230,10 @@ mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsa
|
|||
.note = mutating layout constrained fields cannot statically be checked for valid values
|
||||
.label = mutation of layout constrained field
|
||||
|
||||
mir_build_nan_pattern = cannot use NaN in patterns
|
||||
.note = NaNs compare inequal to everything, even themselves, so this pattern would never match
|
||||
.help = try using the `is_nan` method instead
|
||||
|
||||
mir_build_non_const_path = runtime values cannot be referenced in patterns
|
||||
|
||||
mir_build_non_empty_never_pattern =
|
||||
|
|
|
|||
|
|
@ -583,7 +583,7 @@ impl UnsafeOpKind {
|
|||
suggest_unsafe_block: bool,
|
||||
) {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let parent_owner = tcx.hir().owner(parent_id);
|
||||
let parent_owner = tcx.hir_owner_node(parent_id);
|
||||
let should_suggest = parent_owner.fn_sig().is_some_and(|sig| sig.header.is_unsafe());
|
||||
let unsafe_not_inherited_note = if should_suggest {
|
||||
suggest_unsafe_block.then(|| {
|
||||
|
|
|
|||
|
|
@ -780,9 +780,14 @@ pub struct UnsizedPattern<'tcx> {
|
|||
pub non_sm_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_float_pattern)]
|
||||
pub struct FloatPattern;
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_nan_pattern)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct NaNPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_pointer_pattern)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_apfloat::Float;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::Idx;
|
||||
|
|
@ -16,7 +17,7 @@ use std::cell::Cell;
|
|||
|
||||
use super::PatCtxt;
|
||||
use crate::errors::{
|
||||
FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
|
||||
IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch,
|
||||
NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
|
||||
};
|
||||
|
||||
|
|
@ -317,16 +318,6 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
let param_env = self.param_env;
|
||||
|
||||
let kind = match ty.kind() {
|
||||
ty::Float(_) => {
|
||||
self.saw_const_match_lint.set(true);
|
||||
tcx.emit_node_span_lint(
|
||||
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
id,
|
||||
span,
|
||||
FloatPattern,
|
||||
);
|
||||
return Err(FallbackToOpaqueConst);
|
||||
}
|
||||
// If the type is not structurally comparable, just emit the constant directly,
|
||||
// causing the pattern match code to treat it opaquely.
|
||||
// FIXME: This code doesn't emit errors itself, the caller emits the errors.
|
||||
|
|
@ -486,6 +477,22 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
}
|
||||
}
|
||||
},
|
||||
ty::Float(flt) => {
|
||||
let v = cv.unwrap_leaf();
|
||||
let is_nan = match flt {
|
||||
ty::FloatTy::F32 => v.try_to_f32().unwrap().is_nan(),
|
||||
ty::FloatTy::F64 => v.try_to_f64().unwrap().is_nan(),
|
||||
};
|
||||
if is_nan {
|
||||
// NaNs are not ever equal to anything so they make no sense as patterns.
|
||||
// Also see <https://github.com/rust-lang/rfcs/pull/3535>.
|
||||
let e = tcx.dcx().emit_err(NaNPattern { span });
|
||||
self.saw_const_match_error.set(Some(e));
|
||||
return Err(FallbackToOpaqueConst);
|
||||
} else {
|
||||
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
|
||||
}
|
||||
}
|
||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
|
||||
// The raw pointers we see here have been "vetted" by valtree construction to be
|
||||
// just integers, so we simply allow them.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
|
|||
|
||||
fn add_args(
|
||||
self: Box<Self>,
|
||||
_: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue),
|
||||
_: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue),
|
||||
) {}
|
||||
}
|
||||
throw_machine_stop!(Zst)
|
||||
|
|
|
|||
|
|
@ -394,7 +394,9 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
|||
struct ExtractedHirInfo {
|
||||
function_source_hash: u64,
|
||||
is_async_fn: bool,
|
||||
fn_sig_span: Span,
|
||||
/// The span of the function's signature, extended to the start of `body_span`.
|
||||
/// Must have the same context and filename as the body span.
|
||||
fn_sig_span_extended: Option<Span>,
|
||||
body_span: Span,
|
||||
}
|
||||
|
||||
|
|
@ -407,13 +409,25 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
|
|||
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
|
||||
let hir_body = tcx.hir().body(fn_body_id);
|
||||
|
||||
let is_async_fn = hir_node.fn_sig().is_some_and(|fn_sig| fn_sig.header.is_async());
|
||||
let body_span = get_body_span(tcx, hir_body, def_id);
|
||||
let maybe_fn_sig = hir_node.fn_sig();
|
||||
let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async());
|
||||
|
||||
let mut body_span = hir_body.value.span;
|
||||
|
||||
use rustc_hir::{Closure, Expr, ExprKind, Node};
|
||||
// Unexpand a closure's body span back to the context of its declaration.
|
||||
// This helps with closure bodies that consist of just a single bang-macro,
|
||||
// and also with closure bodies produced by async desugaring.
|
||||
if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) =
|
||||
hir_node
|
||||
{
|
||||
body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span);
|
||||
}
|
||||
|
||||
// The actual signature span is only used if it has the same context and
|
||||
// filename as the body, and precedes the body.
|
||||
let maybe_fn_sig_span = hir_node.fn_sig().map(|fn_sig| fn_sig.span);
|
||||
let fn_sig_span = maybe_fn_sig_span
|
||||
let fn_sig_span_extended = maybe_fn_sig
|
||||
.map(|fn_sig| fn_sig.span)
|
||||
.filter(|&fn_sig_span| {
|
||||
let source_map = tcx.sess.source_map();
|
||||
let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
|
||||
|
|
@ -423,39 +437,15 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
|
|||
&& file_idx(fn_sig_span) == file_idx(body_span)
|
||||
})
|
||||
// If so, extend it to the start of the body span.
|
||||
.map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()))
|
||||
// Otherwise, create a dummy signature span at the start of the body.
|
||||
.unwrap_or_else(|| body_span.shrink_to_lo());
|
||||
.map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()));
|
||||
|
||||
let function_source_hash = hash_mir_source(tcx, hir_body);
|
||||
|
||||
ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span }
|
||||
}
|
||||
|
||||
fn get_body_span<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
hir_body: &rustc_hir::Body<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> Span {
|
||||
let mut body_span = hir_body.value.span;
|
||||
|
||||
if tcx.is_closure_or_coroutine(def_id.to_def_id()) {
|
||||
// If the current function is a closure, and its "body" span was created
|
||||
// by macro expansion or compiler desugaring, try to walk backwards to
|
||||
// the pre-expansion call site or body.
|
||||
body_span = body_span.source_callsite();
|
||||
}
|
||||
|
||||
body_span
|
||||
ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span_extended, body_span }
|
||||
}
|
||||
|
||||
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
|
||||
// FIXME(cjgillot) Stop hashing HIR manually here.
|
||||
let owner = hir_body.id().hir_id.owner;
|
||||
tcx.hir_owner_nodes(owner)
|
||||
.unwrap()
|
||||
.opt_hash_including_bodies
|
||||
.unwrap()
|
||||
.to_smaller_hash()
|
||||
.as_u64()
|
||||
tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_index::bit_set::BitSet;
|
|||
use rustc_middle::mir;
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
|
||||
use super::graph::{BasicCoverageBlock, CoverageGraph};
|
||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
|
||||
use crate::coverage::ExtractedHirInfo;
|
||||
|
||||
mod from_mir;
|
||||
|
|
@ -46,13 +46,26 @@ pub(super) fn generate_coverage_spans(
|
|||
) -> Option<CoverageSpans> {
|
||||
let mut mappings = vec![];
|
||||
|
||||
let sorted_spans =
|
||||
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
|
||||
let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans);
|
||||
mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
|
||||
// Each span produced by the generator represents an ordinary code region.
|
||||
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
|
||||
}));
|
||||
if hir_info.is_async_fn {
|
||||
// An async function desugars into a function that returns a future,
|
||||
// with the user code wrapped in a closure. Any spans in the desugared
|
||||
// outer function will be unhelpful, so just keep the signature span
|
||||
// and ignore all of the spans in the MIR body.
|
||||
if let Some(span) = hir_info.fn_sig_span_extended {
|
||||
mappings.push(BcbMapping { kind: BcbMappingKind::Code(START_BCB), span });
|
||||
}
|
||||
} else {
|
||||
let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
|
||||
mir_body,
|
||||
hir_info,
|
||||
basic_coverage_blocks,
|
||||
);
|
||||
let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans);
|
||||
mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
|
||||
// Each span produced by the generator represents an ordinary code region.
|
||||
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
|
||||
}));
|
||||
}
|
||||
|
||||
if mappings.is_empty() {
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -23,25 +23,21 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
|
|||
hir_info: &ExtractedHirInfo,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
) -> Vec<CoverageSpan> {
|
||||
let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info;
|
||||
let &ExtractedHirInfo { body_span, .. } = hir_info;
|
||||
|
||||
let mut initial_spans = vec![SpanFromMir::for_fn_sig(fn_sig_span)];
|
||||
let mut initial_spans = vec![];
|
||||
|
||||
if is_async_fn {
|
||||
// An async function desugars into a function that returns a future,
|
||||
// with the user code wrapped in a closure. Any spans in the desugared
|
||||
// outer function will be unhelpful, so just keep the signature span
|
||||
// and ignore all of the spans in the MIR body.
|
||||
} else {
|
||||
for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
|
||||
initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data));
|
||||
}
|
||||
for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
|
||||
initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data));
|
||||
}
|
||||
|
||||
// If no spans were extracted from the body, discard the signature span.
|
||||
// FIXME: This preserves existing behavior; consider getting rid of it.
|
||||
if initial_spans.len() == 1 {
|
||||
initial_spans.clear();
|
||||
}
|
||||
// Only add the signature span if we found at least one span in the body.
|
||||
if !initial_spans.is_empty() {
|
||||
// If there is no usable signature span, add a fake one (before refinement)
|
||||
// to avoid an ugly gap between the body start and the first real span.
|
||||
// FIXME: Find a more principled way to solve this problem.
|
||||
let fn_sig_span = hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo());
|
||||
initial_spans.push(SpanFromMir::for_fn_sig(fn_sig_span));
|
||||
}
|
||||
|
||||
initial_spans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb));
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ fn abi_can_unwind(abi: Abi) -> bool {
|
|||
PtxKernel
|
||||
| Msp430Interrupt
|
||||
| X86Interrupt
|
||||
| AmdGpuKernel
|
||||
| EfiApi
|
||||
| AvrInterrupt
|
||||
| AvrNonBlockingInterrupt
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ parse_associated_static_item_not_allowed = associated `static` items are not all
|
|||
|
||||
parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
|
||||
|
||||
parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Rust 2018 or later
|
||||
|
||||
parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
|
||||
.label = to use `async fn`, switch to Rust 2018 or later
|
||||
|
||||
|
|
|
|||
|
|
@ -1588,6 +1588,15 @@ pub(crate) struct AsyncMoveBlockIn2015 {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_async_bound_modifier_in_2015)]
|
||||
pub(crate) struct AsyncBoundModifierIn2015 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub help: HelpUseLatestEdition,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_self_argument_pointer)]
|
||||
pub(crate) struct SelfArgumentPointer {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
|||
// uses a HOF to parse anything, and <source> includes file and
|
||||
// `source_str`.
|
||||
|
||||
/// A variant of 'panictry!' that works on a `Vec<Diagnostic>` instead of a single
|
||||
/// A variant of 'panictry!' that works on a `Vec<DiagnosticBuilder>` instead of a single
|
||||
/// `DiagnosticBuilder`.
|
||||
macro_rules! panictry_buffer {
|
||||
($e:expr) => {{
|
||||
|
|
|
|||
|
|
@ -3288,7 +3288,7 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
err.span_suggestion_verbose(sugg_sp, msg, "=> ".to_string(), applicability);
|
||||
err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
|
||||
}
|
||||
}
|
||||
err
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ impl<'a> Parser<'a> {
|
|||
.with_span_suggestion_verbose(
|
||||
mistyped_const_ident.span,
|
||||
"use the `const` keyword",
|
||||
kw::Const.as_str(),
|
||||
kw::Const,
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
|
|
|||
|
|
@ -1453,7 +1453,7 @@ impl<'a> Parser<'a> {
|
|||
err.span_suggestion_verbose(
|
||||
prev_span,
|
||||
"perhaps you meant to use `struct` here",
|
||||
"struct".to_string(),
|
||||
"struct",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,18 @@ use super::{Parser, PathStyle, TokenType};
|
|||
use crate::errors::{
|
||||
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
|
||||
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
|
||||
InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
|
||||
ReturnTypesUseThinArrow,
|
||||
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
|
||||
NestedCVariadicType, ReturnTypesUseThinArrow,
|
||||
};
|
||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
|
||||
use ast::DUMMY_NODE_ID;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, BoundConstness, BoundPolarity, FnRetTy, GenericBound, GenericBounds,
|
||||
GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef,
|
||||
TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind,
|
||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
|
||||
GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef,
|
||||
TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID,
|
||||
};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
|
@ -880,6 +879,24 @@ impl<'a> Parser<'a> {
|
|||
BoundConstness::Never
|
||||
};
|
||||
|
||||
let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) {
|
||||
self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span);
|
||||
BoundAsyncness::Async(self.prev_token.span)
|
||||
} else if self.may_recover()
|
||||
&& self.token.span.is_rust_2015()
|
||||
&& self.is_kw_followed_by_ident(kw::Async)
|
||||
{
|
||||
self.bump(); // eat `async`
|
||||
self.dcx().emit_err(errors::AsyncBoundModifierIn2015 {
|
||||
span: self.prev_token.span,
|
||||
help: HelpUseLatestEdition::new(),
|
||||
});
|
||||
self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span);
|
||||
BoundAsyncness::Async(self.prev_token.span)
|
||||
} else {
|
||||
BoundAsyncness::Normal
|
||||
};
|
||||
|
||||
let polarity = if self.eat(&token::Question) {
|
||||
BoundPolarity::Maybe(self.prev_token.span)
|
||||
} else if self.eat(&token::Not) {
|
||||
|
|
@ -889,7 +906,7 @@ impl<'a> Parser<'a> {
|
|||
BoundPolarity::Positive
|
||||
};
|
||||
|
||||
Ok(TraitBoundModifiers { constness, polarity })
|
||||
Ok(TraitBoundModifiers { constness, asyncness, polarity })
|
||||
}
|
||||
|
||||
/// Parses a type bound according to:
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue