Merge from rustc
This commit is contained in:
commit
fe69acfdf0
264 changed files with 5364 additions and 3471 deletions
19
Cargo.lock
19
Cargo.lock
|
|
@ -4379,6 +4379,15 @@ dependencies = [
|
|||
"tracing-tree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustdoc-gui-test"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"compiletest",
|
||||
"getopts",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustdoc-json-types"
|
||||
version = "0.1.0"
|
||||
|
|
@ -4972,22 +4981,22 @@ checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8"
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.38"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"syn 2.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ members = [
|
|||
"src/tools/generate-copyright",
|
||||
"src/tools/suggest-tests",
|
||||
"src/tools/generate-windows-sys",
|
||||
"src/tools/rustdoc-gui-test",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
|
|
|
|||
136
RELEASES.md
136
RELEASES.md
|
|
@ -1,3 +1,139 @@
|
|||
Version 1.70.0 (2023-06-01)
|
||||
==========================
|
||||
|
||||
<a id="1.70.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Relax ordering rules for `asm!` operands](https://github.com/rust-lang/rust/pull/105798/)
|
||||
- [Properly allow macro expanded `format_args` invocations to uses captures](https://github.com/rust-lang/rust/pull/106505/)
|
||||
- [Lint ambiguous glob re-exports](https://github.com/rust-lang/rust/pull/107880/)
|
||||
- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/)
|
||||
|
||||
<a id="1.70.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Extend -Cdebuginfo with new options and named aliases](https://github.com/rust-lang/rust/pull/109808/)
|
||||
This provides a smaller version of debuginfo for cases that only need line number information
|
||||
(`-Cdebuginfo=line-tables-only`), which may eventually become the default for `-Cdebuginfo=1`.
|
||||
- [Make `unused_allocation` lint against `Box::new` too](https://github.com/rust-lang/rust/pull/104363/)
|
||||
- [Detect uninhabited types early in const eval](https://github.com/rust-lang/rust/pull/109435/)
|
||||
- [Switch to LLD as default linker for {arm,thumb}v4t-none-eabi](https://github.com/rust-lang/rust/pull/109721/)
|
||||
- [Add tier 3 target `loongarch64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/96971)
|
||||
- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/),
|
||||
- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112)
|
||||
This catches undefined behavior at runtime, and may cause existing code to fail.
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.70.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Document NonZeroXxx layout guarantees](https://github.com/rust-lang/rust/pull/94786/)
|
||||
- [Windows: make `Command` prefer non-verbatim paths](https://github.com/rust-lang/rust/pull/96391/)
|
||||
- [Implement Default for some alloc/core iterators](https://github.com/rust-lang/rust/pull/99929/)
|
||||
- [Fix handling of trailing bare CR in str::lines](https://github.com/rust-lang/rust/pull/100311/)
|
||||
- [allow negative numeric literals in `concat!`](https://github.com/rust-lang/rust/pull/106844/)
|
||||
- [Add documentation about the memory layout of `Cell`](https://github.com/rust-lang/rust/pull/106921/)
|
||||
- [Use `partial_cmp` to implement tuple `lt`/`le`/`ge`/`gt`](https://github.com/rust-lang/rust/pull/108157/)
|
||||
- [Stabilize `atomic_as_ptr`](https://github.com/rust-lang/rust/pull/108419/)
|
||||
- [Stabilize `nonnull_slice_from_raw_parts`](https://github.com/rust-lang/rust/pull/97506/)
|
||||
- [Partial stabilization of `once_cell`](https://github.com/rust-lang/rust/pull/105587/)
|
||||
- [Stabilize `nonzero_min_max`](https://github.com/rust-lang/rust/pull/106633/)
|
||||
- [Flatten/inline format_args!() and (string and int) literal arguments into format_args!()](https://github.com/rust-lang/rust/pull/106824/)
|
||||
- [Stabilize movbe target feature](https://github.com/rust-lang/rust/pull/107711/)
|
||||
- [don't splice from files into pipes in io::copy](https://github.com/rust-lang/rust/pull/108283/)
|
||||
- [Add a builtin unstable `FnPtr` trait that is implemented for all function pointers](https://github.com/rust-lang/rust/pull/108080/)
|
||||
This extends `Debug`, `Pointer`, `Hash`, `PartialEq`, `Eq`, `PartialOrd`, and `Ord`
|
||||
implementations for function pointers with all ABIs.
|
||||
|
||||
<a id="1.70.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`NonZero*::MIN/MAX`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html#associatedconstant.MIN)
|
||||
- [`BinaryHeap::retain`](https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.retain)
|
||||
- [`Default for std::collections::binary_heap::IntoIter`](https://doc.rust-lang.org/stable/std/collections/binary_heap/struct.IntoIter.html)
|
||||
- [`Default for std::collections::btree_map::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoIter.html)
|
||||
- [`Default for std::collections::btree_map::{IntoKeys, Keys}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html)
|
||||
- [`Default for std::collections::btree_map::{IntoValues, Values}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html)
|
||||
- [`Default for std::collections::btree_map::Range`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.Range.html)
|
||||
- [`Default for std::collections::btree_set::{IntoIter, Iter}`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.IntoIter.html)
|
||||
- [`Default for std::collections::btree_set::Range`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.Range.html)
|
||||
- [`Default for std::collections::linked_list::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/alloc/collections/linked_list/struct.IntoIter.html)
|
||||
- [`Default for std::vec::IntoIter`](https://doc.rust-lang.org/stable/alloc/vec/struct.IntoIter.html#impl-Default-for-IntoIter%3CT,+A%3E)
|
||||
- [`Default for std::iter::Chain`](https://doc.rust-lang.org/stable/std/iter/struct.Chain.html)
|
||||
- [`Default for std::iter::Cloned`](https://doc.rust-lang.org/stable/std/iter/struct.Cloned.html)
|
||||
- [`Default for std::iter::Copied`](https://doc.rust-lang.org/stable/std/iter/struct.Copied.html)
|
||||
- [`Default for std::iter::Enumerate`](https://doc.rust-lang.org/stable/std/iter/struct.Enumerate.html)
|
||||
- [`Default for std::iter::Flatten`](https://doc.rust-lang.org/stable/std/iter/struct.Flatten.html)
|
||||
- [`Default for std::iter::Fuse`](https://doc.rust-lang.org/stable/std/iter/struct.Fuse.html)
|
||||
- [`Default for std::iter::Rev`](https://doc.rust-lang.org/stable/std/iter/struct.Rev.html)
|
||||
- [`Default for std::slice::Iter`](https://doc.rust-lang.org/stable/std/slice/struct.Iter.html)
|
||||
- [`Default for std::slice::IterMut`](https://doc.rust-lang.org/stable/std/slice/struct.IterMut.html)
|
||||
- [`Rc::into_inner`](https://doc.rust-lang.org/stable/alloc/rc/struct.Rc.html#method.into_inner)
|
||||
- [`Arc::into_inner`](https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html#method.into_inner)
|
||||
- [`std::cell::OnceCell`](https://doc.rust-lang.org/stable/std/cell/struct.OnceCell.html)
|
||||
- [`Option::is_some_and`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.is_some_and)
|
||||
- [`NonNull::slice_from_raw_parts`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.slice_from_raw_parts)
|
||||
- [`Result::is_ok_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_ok_and)
|
||||
- [`Result::is_err_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_err_and)
|
||||
- [`std::sync::atomic::Atomic*::as_ptr`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicU8.html#method.as_ptr)
|
||||
- [`std::io::IsTerminal`](https://doc.rust-lang.org/stable/std/io/trait.IsTerminal.html)
|
||||
- [`std::os::linux::net::SocketAddrExt`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.SocketAddrExt.html)
|
||||
- [`std::os::unix::net::UnixDatagram::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.bind_addr)
|
||||
- [`std::os::unix::net::UnixDatagram::connect_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.connect_addr)
|
||||
- [`std::os::unix::net::UnixDatagram::send_to_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.send_to_addr)
|
||||
- [`std::os::unix::net::UnixListener::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixListener.html#method.bind_addr)
|
||||
- [`std::path::Path::as_mut_os_str`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.as_mut_os_str)
|
||||
- [`std::sync::OnceLock`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html)
|
||||
|
||||
<a id="1.70.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- [Add `CARGO_PKG_README`](https://github.com/rust-lang/cargo/pull/11645/)
|
||||
- [Make `sparse` the default protocol for crates.io](https://github.com/rust-lang/cargo/pull/11791/)
|
||||
- [Accurately show status when downgrading dependencies](https://github.com/rust-lang/cargo/pull/11839/)
|
||||
- [Use registry.default for login/logout](https://github.com/rust-lang/cargo/pull/11949/)
|
||||
- [Stabilize `cargo logout`](https://github.com/rust-lang/cargo/pull/11950/)
|
||||
|
||||
<a id="1.70.0-Misc"></a>
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
- [Stabilize rustdoc `--test-run-directory`](https://github.com/rust-lang/rust/pull/103682/)
|
||||
|
||||
<a id="1.70.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- [Prevent stable `libtest` from supporting `-Zunstable-options`](https://github.com/rust-lang/rust/pull/109044/)
|
||||
- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/)
|
||||
- [WebAssembly targets enable `sign-ext` and `mutable-globals` features in codegen](https://github.com/rust-lang/rust/issues/109807)
|
||||
This may cause incompatibility with older execution environments.
|
||||
- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112)
|
||||
This catches undefined behavior at runtime, and may cause existing code to fail.
|
||||
|
||||
<a id="1.70.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Upgrade to LLVM 16](https://github.com/rust-lang/rust/pull/109474/)
|
||||
- [Use SipHash-1-3 instead of SipHash-2-4 for StableHasher](https://github.com/rust-lang/rust/pull/107925/)
|
||||
|
||||
Version 1.69.0 (2023-04-20)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
|||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
|
|
|
|||
|
|
@ -1635,34 +1635,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
|
||||
///
|
||||
/// Depending on the origin of the StorageDeadOrDrop, this may be
|
||||
/// reported as either a drop or an illegal mutation of a borrowed value.
|
||||
/// The latter is preferred when the this is a drop triggered by a
|
||||
/// reassignment, as it's more user friendly to report a problem with the
|
||||
/// explicit assignment than the implicit drop.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn report_storage_dead_or_drop_of_borrowed(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place_span: (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) {
|
||||
// It's sufficient to check the last desugaring as Replace is the last
|
||||
// one to be applied.
|
||||
if let Some(DesugaringKind::Replace) = place_span.1.desugaring_kind() {
|
||||
self.report_illegal_mutation_of_borrowed(location, place_span, borrow)
|
||||
} else {
|
||||
self.report_borrowed_value_does_not_live_long_enough(
|
||||
location,
|
||||
borrow,
|
||||
place_span,
|
||||
Some(WriteKind::StorageDeadOrDrop),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// This means that some data referenced by `borrow` needs to live
|
||||
/// past the point where the StorageDeadOrDrop of `place` occurs.
|
||||
/// This is usually interpreted as meaning that `place` has too
|
||||
|
|
|
|||
|
|
@ -641,13 +641,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let Some(hir::Node::Item(item)) = node else { return; };
|
||||
let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
|
||||
let body = self.infcx.tcx.hir().body(body_id);
|
||||
let mut assign_span = span;
|
||||
// Drop desugaring is done at MIR build so it's not in the HIR
|
||||
if let Some(DesugaringKind::Replace) = span.desugaring_kind() {
|
||||
assign_span.remove_mark();
|
||||
}
|
||||
|
||||
let mut v = V { assign_span, err, ty, suggested: false };
|
||||
let mut v = V { assign_span: span, err, ty, suggested: false };
|
||||
v.visit_body(body);
|
||||
if !v.suggested {
|
||||
err.help(format!(
|
||||
|
|
|
|||
|
|
@ -112,11 +112,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
TerminatorKind::SwitchInt { discr, targets: _ } => {
|
||||
self.consume_operand(location, discr);
|
||||
}
|
||||
TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
|
||||
TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => {
|
||||
let write_kind =
|
||||
if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
|
||||
self.access_place(
|
||||
location,
|
||||
*drop_place,
|
||||
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
||||
(AccessDepth::Drop, Write(write_kind)),
|
||||
LocalMutationIsAllowed::Yes,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -685,17 +685,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
|||
TerminatorKind::SwitchInt { discr, targets: _ } => {
|
||||
self.consume_operand(loc, (discr, span), flow_state);
|
||||
}
|
||||
TerminatorKind::Drop { place, target: _, unwind: _ } => {
|
||||
TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
|
||||
debug!(
|
||||
"visit_terminator_drop \
|
||||
loc: {:?} term: {:?} place: {:?} span: {:?}",
|
||||
loc, term, place, span
|
||||
);
|
||||
|
||||
let write_kind =
|
||||
if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
|
||||
self.access_place(
|
||||
loc,
|
||||
(*place, span),
|
||||
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
||||
(AccessDepth::Drop, Write(write_kind)),
|
||||
LocalMutationIsAllowed::Yes,
|
||||
flow_state,
|
||||
);
|
||||
|
|
@ -885,6 +887,7 @@ enum ReadKind {
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum WriteKind {
|
||||
StorageDeadOrDrop,
|
||||
Replace,
|
||||
MutableBorrow(BorrowKind),
|
||||
Mutate,
|
||||
Move,
|
||||
|
|
@ -1132,13 +1135,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
this.buffer_error(err);
|
||||
}
|
||||
WriteKind::StorageDeadOrDrop => this
|
||||
.report_storage_dead_or_drop_of_borrowed(location, place_span, borrow),
|
||||
.report_borrowed_value_does_not_live_long_enough(
|
||||
location,
|
||||
borrow,
|
||||
place_span,
|
||||
Some(WriteKind::StorageDeadOrDrop),
|
||||
),
|
||||
WriteKind::Mutate => {
|
||||
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
|
||||
}
|
||||
WriteKind::Move => {
|
||||
this.report_move_out_while_borrowed(location, place_span, borrow)
|
||||
}
|
||||
WriteKind::Replace => {
|
||||
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
|
||||
}
|
||||
}
|
||||
Control::Break
|
||||
}
|
||||
|
|
@ -1982,12 +1993,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
Reservation(
|
||||
WriteKind::Move
|
||||
| WriteKind::Replace
|
||||
| WriteKind::StorageDeadOrDrop
|
||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||
| WriteKind::MutableBorrow(BorrowKind::Shallow),
|
||||
)
|
||||
| Write(
|
||||
WriteKind::Move
|
||||
| WriteKind::Replace
|
||||
| WriteKind::StorageDeadOrDrop
|
||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||
| WriteKind::MutableBorrow(BorrowKind::Shallow),
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use rustc_index::bit_set::HybridBitSet;
|
|||
use rustc_index::interval::IntervalSet;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
|
||||
use rustc_middle::traits::query::DropckOutlivesResult;
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
|
||||
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
use std::rc::Rc;
|
||||
|
|
|
|||
|
|
@ -233,10 +233,19 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
ExprKind::Cast(local_expr, _) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::If(local_expr, _, _) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::Index(prefix, suffix) => {
|
||||
self.manage_cond_expr(prefix);
|
||||
self.manage_cond_expr(suffix);
|
||||
}
|
||||
ExprKind::Let(_, local_expr, _) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::Match(local_expr, _) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::MethodCall(call) => {
|
||||
for arg in &mut call.args {
|
||||
self.manage_cond_expr(arg);
|
||||
|
|
@ -295,17 +304,14 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
| ExprKind::Continue(_)
|
||||
| ExprKind::Err
|
||||
| ExprKind::Field(_, _)
|
||||
| ExprKind::FormatArgs(_)
|
||||
| ExprKind::ForLoop(_, _, _, _)
|
||||
| ExprKind::If(_, _, _)
|
||||
| ExprKind::FormatArgs(_)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::InlineAsm(_)
|
||||
| ExprKind::OffsetOf(_, _)
|
||||
| ExprKind::Let(_, _, _)
|
||||
| ExprKind::Lit(_)
|
||||
| ExprKind::Loop(_, _, _)
|
||||
| ExprKind::MacCall(_)
|
||||
| ExprKind::Match(_, _)
|
||||
| ExprKind::OffsetOf(_, _)
|
||||
| ExprKind::Path(_, _)
|
||||
| ExprKind::Ret(_)
|
||||
| ExprKind::Try(_)
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
| TerminatorKind::GeneratorDrop => {
|
||||
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
|
||||
}
|
||||
TerminatorKind::Drop { place, target, unwind: _ } => {
|
||||
TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
|
||||
let drop_place = codegen_place(fx, *place);
|
||||
crate::abi::codegen_drop(fx, source_info, drop_place);
|
||||
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||
self.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
ty::EarlyBinder(value),
|
||||
ty::EarlyBinder::new(value),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ pub fn sanitize_attrs<'ll>(
|
|||
|
||||
attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
|
||||
}
|
||||
if enabled.contains(SanitizerSet::SAFESTACK) {
|
||||
attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx));
|
||||
}
|
||||
attrs
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>(
|
|||
let callee = cx.tcx.subst_and_normalize_erasing_regions(
|
||||
instance.substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
ty::EarlyBinder(callee),
|
||||
ty::EarlyBinder::new(callee),
|
||||
);
|
||||
let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
|
||||
cx.dbg_scope_fn(callee, callee_fn_abi, None)
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ pub enum AttributeKind {
|
|||
AllocSize = 37,
|
||||
AllocatedPointer = 38,
|
||||
AllocAlign = 39,
|
||||
SanitizeSafeStack = 40,
|
||||
}
|
||||
|
||||
/// LLVMIntPredicate
|
||||
|
|
|
|||
|
|
@ -1188,6 +1188,9 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
|
|||
if sanitizer.contains(SanitizerSet::HWADDRESS) {
|
||||
link_sanitizer_runtime(sess, linker, "hwasan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::SAFESTACK) {
|
||||
link_sanitizer_runtime(sess, linker, "safestack");
|
||||
}
|
||||
}
|
||||
|
||||
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
|
||||
|
|
|
|||
|
|
@ -1256,7 +1256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
MergingSucc::False
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Drop { place, target, unwind } => {
|
||||
mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
|
||||
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||
self.cx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
ty::EarlyBinder(value),
|
||||
ty::EarlyBinder::new(value),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -497,7 +497,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
.try_subst_mir_and_normalize_erasing_regions(
|
||||
*self.tcx,
|
||||
self.param_env,
|
||||
ty::EarlyBinder(value),
|
||||
ty::EarlyBinder::new(value),
|
||||
)
|
||||
.map_err(|_| err_inval!(TooGeneric))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
Drop { place, target, unwind } => {
|
||||
Drop { place, target, unwind, replace: _ } => {
|
||||
let frame = self.frame();
|
||||
let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
|
||||
let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::fx::{FxHashMap, FxHasher};
|
||||
#[cfg(parallel_compiler)]
|
||||
use crate::sync::is_dyn_thread_safe;
|
||||
use crate::sync::{CacheAligned, Lock, LockGuard};
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::hash_map::RawEntryMut;
|
||||
|
|
@ -18,6 +20,11 @@ pub const SHARDS: usize = 1 << SHARD_BITS;
|
|||
|
||||
/// An array of cache-line aligned inner locked structures with convenience methods.
|
||||
pub struct Sharded<T> {
|
||||
/// This mask is used to ensure that accesses are inbounds of `shards`.
|
||||
/// When dynamic thread safety is off, this field is set to 0 causing only
|
||||
/// a single shard to be used for greater cache efficiency.
|
||||
#[cfg(parallel_compiler)]
|
||||
mask: usize,
|
||||
shards: [CacheAligned<Lock<T>>; SHARDS],
|
||||
}
|
||||
|
||||
|
|
@ -31,31 +38,54 @@ impl<T: Default> Default for Sharded<T> {
|
|||
impl<T> Sharded<T> {
|
||||
#[inline]
|
||||
pub fn new(mut value: impl FnMut() -> T) -> Self {
|
||||
Sharded { shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))) }
|
||||
Sharded {
|
||||
#[cfg(parallel_compiler)]
|
||||
mask: if is_dyn_thread_safe() { SHARDS - 1 } else { 0 },
|
||||
shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn mask(&self) -> usize {
|
||||
#[cfg(parallel_compiler)]
|
||||
{
|
||||
if SHARDS == 1 { 0 } else { self.mask }
|
||||
}
|
||||
#[cfg(not(parallel_compiler))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn count(&self) -> usize {
|
||||
// `self.mask` is always one below the used shard count
|
||||
self.mask() + 1
|
||||
}
|
||||
|
||||
/// The shard is selected by hashing `val` with `FxHasher`.
|
||||
#[inline]
|
||||
pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> {
|
||||
if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) }
|
||||
self.get_shard_by_hash(if SHARDS == 1 { 0 } else { make_hash(val) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> {
|
||||
&self.shards[get_shard_index_by_hash(hash)].0
|
||||
self.get_shard_by_index(get_shard_hash(hash))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> {
|
||||
&self.shards[i].0
|
||||
// SAFETY: The index get ANDed with the mask, ensuring it is always inbounds.
|
||||
unsafe { &self.shards.get_unchecked(i & self.mask()).0 }
|
||||
}
|
||||
|
||||
pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {
|
||||
(0..SHARDS).map(|i| self.shards[i].0.lock()).collect()
|
||||
(0..self.count()).map(|i| self.get_shard_by_index(i).lock()).collect()
|
||||
}
|
||||
|
||||
pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> {
|
||||
(0..SHARDS).map(|i| self.shards[i].0.try_lock()).collect()
|
||||
(0..self.count()).map(|i| self.get_shard_by_index(i).try_lock()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,11 +166,9 @@ pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
|
|||
/// `hash` can be computed with any hasher, so long as that hasher is used
|
||||
/// consistently for each `Sharded` instance.
|
||||
#[inline]
|
||||
#[allow(clippy::modulo_one)]
|
||||
pub fn get_shard_index_by_hash(hash: u64) -> usize {
|
||||
fn get_shard_hash(hash: u64) -> usize {
|
||||
let hash_len = mem::size_of::<usize>();
|
||||
// Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
|
||||
// hashbrown also uses the lowest bits, so we can't use those
|
||||
let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
|
||||
bits % SHARDS
|
||||
(hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
/// **Note:** This function doesn't interpret argument 0 in any special way.
|
||||
/// If this function is intended to be used with command line arguments,
|
||||
/// `argv[0]` must be removed prior to calling it manually.
|
||||
pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
|
||||
let mut args = Vec::new();
|
||||
for arg in at_args {
|
||||
|
|
|
|||
|
|
@ -250,6 +250,16 @@ fn run_compiler(
|
|||
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
|
||||
>,
|
||||
) -> interface::Result<()> {
|
||||
// Throw away the first argument, the name of the binary.
|
||||
// In case of at_args being empty, as might be the case by
|
||||
// passing empty argument array to execve under some platforms,
|
||||
// just use an empty slice.
|
||||
//
|
||||
// This situation was possible before due to arg_expand_all being
|
||||
// called before removing the argument, enabling a crash by calling
|
||||
// the compiler with @empty_file as argv[0] and no more arguments.
|
||||
let at_args = at_args.get(1..).unwrap_or_default();
|
||||
|
||||
let args = args::arg_expand_all(at_args);
|
||||
|
||||
let Some(matches) = handle_options(&args) else { return Ok(()) };
|
||||
|
|
@ -1074,9 +1084,6 @@ fn print_flag_list<T>(
|
|||
/// So with all that in mind, the comments below have some more detail about the
|
||||
/// contortions done here to get things to work out correctly.
|
||||
pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
||||
// Throw away the first argument, the name of the binary
|
||||
let args = &args[1..];
|
||||
|
||||
if args.is_empty() {
|
||||
// user did not write `-v` nor `-Z unstable-options`, so do not
|
||||
// include that extra information.
|
||||
|
|
|
|||
|
|
@ -1159,7 +1159,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// those that do.
|
||||
self.one_bound_for_assoc_type(
|
||||
|| traits::supertraits(tcx, trait_ref),
|
||||
trait_ref.print_only_trait_path(),
|
||||
trait_ref.skip_binder().print_only_trait_name(),
|
||||
binding.item_name,
|
||||
path_span,
|
||||
match binding.kind {
|
||||
|
|
@ -1278,7 +1278,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// params (and trait ref's late bound params). This logic is very similar to
|
||||
// `Predicate::subst_supertrait`, and it's no coincidence why.
|
||||
let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
|
||||
let subst_output = ty::EarlyBinder(shifted_output).subst(tcx, substs);
|
||||
let subst_output = ty::EarlyBinder::new(shifted_output).subst(tcx, substs);
|
||||
|
||||
let bound_vars = tcx.late_bound_vars(binding.hir_id);
|
||||
ty::Binder::bind_with_vars(subst_output, bound_vars)
|
||||
|
|
|
|||
|
|
@ -794,14 +794,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
})
|
||||
});
|
||||
debug!(%ty);
|
||||
collected_tys.insert(def_id, ty::EarlyBinder(ty));
|
||||
collected_tys.insert(def_id, ty::EarlyBinder::new(ty));
|
||||
}
|
||||
Err(err) => {
|
||||
let reported = tcx.sess.delay_span_bug(
|
||||
return_span,
|
||||
format!("could not fully resolve: {ty} => {err:?}"),
|
||||
);
|
||||
collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported)));
|
||||
collected_tys.insert(def_id, ty::EarlyBinder::new(tcx.ty_error(reported)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -901,7 +901,7 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
if trait_m.fn_has_self_parameter =>
|
||||
{
|
||||
let ty = trait_sig.inputs()[0];
|
||||
let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
|
||||
let sugg = match ExplicitSelf::determine(ty, |ty| ty == impl_trait_ref.self_ty()) {
|
||||
ExplicitSelf::ByValue => "self".to_owned(),
|
||||
ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
|
||||
ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
|||
// We don't need to normalize this param-env or anything, since we're only
|
||||
// substituting it with free params, so no additional param-env normalization
|
||||
// can occur on top of what has been done in the param_env query itself.
|
||||
let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id))
|
||||
let param_env = ty::EarlyBinder::new(tcx.param_env(adt_def_id))
|
||||
.subst(tcx, adt_to_impl_substs)
|
||||
.with_constness(tcx.constness(drop_impl_def_id));
|
||||
|
||||
|
|
|
|||
|
|
@ -1398,7 +1398,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
}
|
||||
let mut param_count = CountParams::default();
|
||||
let has_region = pred.visit_with(&mut param_count).is_break();
|
||||
let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs);
|
||||
let substituted_pred = ty::EarlyBinder::new(pred).subst(tcx, substs);
|
||||
// Don't check non-defaulted params, dependent defaults (including lifetimes)
|
||||
// or preds with multiple params.
|
||||
if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
|
||||
|
|
|
|||
|
|
@ -1124,7 +1124,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
|
|||
bug!("unexpected sort of node in fn_sig(): {:?}", x);
|
||||
}
|
||||
};
|
||||
ty::EarlyBinder(output)
|
||||
ty::EarlyBinder::new(output)
|
||||
}
|
||||
|
||||
fn infer_return_ty_for_fn_sig<'tcx>(
|
||||
|
|
@ -1312,7 +1312,7 @@ fn impl_trait_ref(
|
|||
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||
)
|
||||
})
|
||||
.map(ty::EarlyBinder)
|
||||
.map(ty::EarlyBinder::new)
|
||||
}
|
||||
|
||||
fn check_impl_constness(
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ pub(super) fn explicit_item_bounds(
|
|||
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
|
||||
let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item();
|
||||
let opaque_ty = item.expect_opaque_ty();
|
||||
return ty::EarlyBinder(opaque_type_bounds(
|
||||
return ty::EarlyBinder::new(opaque_type_bounds(
|
||||
tcx,
|
||||
opaque_def_id.expect_local(),
|
||||
opaque_ty.bounds,
|
||||
|
|
@ -124,7 +124,7 @@ pub(super) fn explicit_item_bounds(
|
|||
}
|
||||
_ => bug!("item_bounds called on {:?}", def_id),
|
||||
};
|
||||
ty::EarlyBinder(bounds)
|
||||
ty::EarlyBinder::new(bounds)
|
||||
}
|
||||
|
||||
pub(super) fn item_bounds(
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
|||
return map[&assoc_item.trait_item_def_id.unwrap()];
|
||||
}
|
||||
Err(_) => {
|
||||
return ty::EarlyBinder(tcx.ty_error_with_message(
|
||||
return ty::EarlyBinder::new(tcx.ty_error_with_message(
|
||||
DUMMY_SP,
|
||||
"Could not collect return position impl trait in trait tys",
|
||||
));
|
||||
|
|
@ -497,7 +497,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
|||
bug!("unexpected sort of node in type_of(): {:?}", x);
|
||||
}
|
||||
};
|
||||
ty::EarlyBinder(output)
|
||||
ty::EarlyBinder::new(output)
|
||||
}
|
||||
|
||||
fn infer_placeholder_type<'a>(
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
ty::EarlyBinder(required_predicates)
|
||||
ty::EarlyBinder::new(required_predicates)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,12 +68,13 @@ pub(super) fn infer_predicates(
|
|||
// Therefore mark `predicates_added` as true and which will ensure
|
||||
// we walk the crates again and re-calculate predicates for all
|
||||
// items.
|
||||
let item_predicates_len: usize =
|
||||
global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.0.len());
|
||||
let item_predicates_len: usize = global_inferred_outlives
|
||||
.get(&item_did.to_def_id())
|
||||
.map_or(0, |p| p.as_ref().skip_binder().len());
|
||||
if item_required_predicates.len() > item_predicates_len {
|
||||
predicates_added = true;
|
||||
global_inferred_outlives
|
||||
.insert(item_did.to_def_id(), ty::EarlyBinder(item_required_predicates));
|
||||
.insert(item_did.to_def_id(), ty::EarlyBinder::new(item_required_predicates));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +138,9 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
// 'a` holds for `Foo`.
|
||||
debug!("Adt");
|
||||
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
|
||||
for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 {
|
||||
for (unsubstituted_predicate, &span) in
|
||||
unsubstituted_predicates.as_ref().skip_binder()
|
||||
{
|
||||
// `unsubstituted_predicate` is `U: 'b` in the
|
||||
// example above. So apply the substitution to
|
||||
// get `T: 'a` (or `predicate`):
|
||||
|
|
@ -251,7 +254,7 @@ fn check_explicit_predicates<'tcx>(
|
|||
);
|
||||
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
|
||||
|
||||
for (outlives_predicate, &span) in &explicit_predicates.0 {
|
||||
for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() {
|
||||
debug!("outlives_predicate = {:?}", &outlives_predicate);
|
||||
|
||||
// Careful: If we are inferring the effects of a `dyn Trait<..>`
|
||||
|
|
|
|||
|
|
@ -98,24 +98,27 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
|
|||
let predicates = global_inferred_outlives
|
||||
.iter()
|
||||
.map(|(&def_id, set)| {
|
||||
let predicates = &*tcx.arena.alloc_from_iter(set.0.iter().filter_map(
|
||||
|(ty::OutlivesPredicate(kind1, region2), &span)| {
|
||||
match kind1.unpack() {
|
||||
GenericArgKind::Type(ty1) => Some((
|
||||
ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)),
|
||||
span,
|
||||
)),
|
||||
GenericArgKind::Lifetime(region1) => Some((
|
||||
ty::Clause::RegionOutlives(ty::OutlivesPredicate(region1, *region2)),
|
||||
span,
|
||||
)),
|
||||
GenericArgKind::Const(_) => {
|
||||
// Generic consts don't impose any constraints.
|
||||
None
|
||||
let predicates =
|
||||
&*tcx.arena.alloc_from_iter(set.as_ref().skip_binder().iter().filter_map(
|
||||
|(ty::OutlivesPredicate(kind1, region2), &span)| {
|
||||
match kind1.unpack() {
|
||||
GenericArgKind::Type(ty1) => Some((
|
||||
ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)),
|
||||
span,
|
||||
)),
|
||||
GenericArgKind::Lifetime(region1) => Some((
|
||||
ty::Clause::RegionOutlives(ty::OutlivesPredicate(
|
||||
region1, *region2,
|
||||
)),
|
||||
span,
|
||||
)),
|
||||
GenericArgKind::Const(_) => {
|
||||
// Generic consts don't impose any constraints.
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
));
|
||||
},
|
||||
));
|
||||
(def_id, predicates)
|
||||
})
|
||||
.collect();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
|
|||
|
||||
hir_typeck_convert_to_str = try converting the passed type into a `&str`
|
||||
|
||||
hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
|
||||
|
||||
hir_typeck_expected_default_return_type = expected `()` because of default return type
|
||||
|
||||
hir_typeck_expected_return_type = expected `{$expected}` because of return type
|
||||
|
|
@ -59,8 +61,8 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la
|
|||
hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
|
||||
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
|
||||
|
||||
hir_typeck_method_call_on_unknown_type =
|
||||
the type of this value must be known to call a method on a raw pointer on it
|
||||
hir_typeck_method_call_on_unknown_raw_pointee =
|
||||
cannot call a method on a raw pointer with an unknown pointee type
|
||||
|
||||
hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
|
||||
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ pub struct StructExprNonExhaustive {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_method_call_on_unknown_type, code = "E0699")]
|
||||
pub struct MethodCallOnUnknownType {
|
||||
#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")]
|
||||
pub struct MethodCallOnUnknownRawPointee {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
@ -319,3 +319,11 @@ pub struct CandidateTraitNote {
|
|||
pub item_name: Ident,
|
||||
pub action_or_ty: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_ctor_is_private, code = "E0603")]
|
||||
pub struct CtorIsPrivate {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::callee::{self, DeferredCallResolution};
|
||||
use crate::errors::CtorIsPrivate;
|
||||
use crate::method::{self, MethodCallee, SelfSource};
|
||||
use crate::rvalue_scopes;
|
||||
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
|
||||
|
|
@ -1207,6 +1208,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
match ty.normalized.ty_adt_def() {
|
||||
Some(adt_def) if adt_def.has_ctor() => {
|
||||
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
|
||||
// Check the visibility of the ctor.
|
||||
let vis = tcx.visibility(ctor_def_id);
|
||||
if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) {
|
||||
tcx.sess
|
||||
.emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) });
|
||||
}
|
||||
let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
|
||||
let user_substs = Self::user_substs_for_adt(ty);
|
||||
user_self_ty = user_substs.user_self_ty;
|
||||
|
|
@ -1379,7 +1386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// the referenced item.
|
||||
let ty = tcx.type_of(def_id);
|
||||
assert!(!substs.has_escaping_bound_vars());
|
||||
assert!(!ty.0.has_escaping_bound_vars());
|
||||
assert!(!ty.skip_binder().has_escaping_bound_vars());
|
||||
let ty_substituted = self.normalize(span, ty.subst(tcx, substs));
|
||||
|
||||
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use super::CandidateSource;
|
|||
use super::MethodError;
|
||||
use super::NoMatchData;
|
||||
|
||||
use crate::errors::MethodCallOnUnknownType;
|
||||
use crate::errors::MethodCallOnUnknownRawPointee;
|
||||
use crate::FnCtxt;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -438,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// so we do a future-compat lint here for the 2015 edition
|
||||
// (see https://github.com/rust-lang/rust/issues/46906)
|
||||
if self.tcx.sess.rust_2018() {
|
||||
self.tcx.sess.emit_err(MethodCallOnUnknownType { span });
|
||||
self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
|
||||
} else {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
) -> impl Iterator<Item = ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let bounds = tcx.item_bounds(alias_ty.def_id);
|
||||
trace!("{:#?}", bounds.0);
|
||||
trace!("{:#?}", bounds.skip_binder());
|
||||
bounds
|
||||
.subst_iter(tcx, alias_ty.substs)
|
||||
.filter_map(|p| p.to_opt_type_outlives())
|
||||
|
|
|
|||
|
|
@ -952,6 +952,10 @@ pub trait LintContext: Sized {
|
|||
db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace));
|
||||
db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace));
|
||||
}
|
||||
BuiltinLintDiagnostics::HiddenGlobReexports { name, namespace, glob_reexport_span, private_item_span } => {
|
||||
db.span_label(glob_reexport_span, format!("the name `{}` in the {} namespace is supposed to be publicly re-exported here", name, namespace));
|
||||
db.span_label(private_item_span, "but the private item here shadows it");
|
||||
}
|
||||
}
|
||||
// Rewrap `db`, and pass control to the user.
|
||||
decorate(db)
|
||||
|
|
|
|||
|
|
@ -242,7 +242,9 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> {
|
|||
|
||||
struct QueryMapExpectationsWrapper<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
/// HirId of the currently investigated element.
|
||||
cur: HirId,
|
||||
/// Level map for `cur`.
|
||||
specs: ShallowLintLevelMap,
|
||||
expectations: Vec<(LintExpectationId, LintExpectation)>,
|
||||
unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>,
|
||||
|
|
@ -255,11 +257,11 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> {
|
|||
self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
|
||||
}
|
||||
fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
|
||||
let specs = self.specs.specs.get_mut_or_insert_default(self.cur.local_id);
|
||||
specs.clear();
|
||||
specs.insert(id, lvl);
|
||||
self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl);
|
||||
}
|
||||
fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
|
||||
// We cannot use `tcx.lint_level_at_node` because we want to know in which order the
|
||||
// attributes have been inserted, in particular whether an `expect` follows a `forbid`.
|
||||
self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
|
||||
}
|
||||
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
|
||||
|
|
@ -355,7 +357,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
|
|||
|
||||
impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
|
||||
fn add_id(&mut self, hir_id: HirId) {
|
||||
// Change both the `HirId` and the associated specs.
|
||||
self.provider.cur = hir_id;
|
||||
self.provider.specs.specs.clear();
|
||||
self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3272,6 +3272,43 @@ declare_lint! {
|
|||
"ambiguous glob re-exports",
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `hidden_glob_reexports` lint detects cases where glob re-export items are shadowed by
|
||||
/// private items.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(hidden_glob_reexports)]
|
||||
///
|
||||
/// pub mod upstream {
|
||||
/// mod inner { pub struct Foo {}; pub struct Bar {}; }
|
||||
/// pub use self::inner::*;
|
||||
/// struct Foo {} // private item shadows `inner::Foo`
|
||||
/// }
|
||||
///
|
||||
/// // mod downstream {
|
||||
/// // fn test() {
|
||||
/// // let _ = crate::upstream::Foo; // inaccessible
|
||||
/// // }
|
||||
/// // }
|
||||
///
|
||||
/// pub fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This was previously accepted without any errors or warnings but it could silently break a
|
||||
/// crate's downstream user code. If the `struct Foo` was added, `dep::inner::Foo` would
|
||||
/// silently become inaccessible and trigger a "`struct `Foo` is private`" visibility error at
|
||||
/// the downstream use site.
|
||||
pub HIDDEN_GLOB_REEXPORTS,
|
||||
Warn,
|
||||
"name introduced by a private item shadows a name introduced by a public glob re-export",
|
||||
}
|
||||
|
||||
declare_lint_pass! {
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// that are used by other parts of the compiler.
|
||||
|
|
@ -3304,6 +3341,7 @@ declare_lint_pass! {
|
|||
FORBIDDEN_LINT_GROUPS,
|
||||
FUNCTION_ITEM_REFERENCES,
|
||||
FUZZY_PROVENANCE_CASTS,
|
||||
HIDDEN_GLOB_REEXPORTS,
|
||||
ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
IMPLIED_BOUNDS_ENTAILMENT,
|
||||
|
|
|
|||
|
|
@ -540,6 +540,16 @@ pub enum BuiltinLintDiagnostics {
|
|||
/// Span where the same name is also re-exported.
|
||||
duplicate_reexport_span: Span,
|
||||
},
|
||||
HiddenGlobReexports {
|
||||
/// The name of the local binding which shadows the glob re-export.
|
||||
name: String,
|
||||
/// The namespace for which the shadowing occurred in.
|
||||
namespace: String,
|
||||
/// The glob reexport that is shadowed by the local binding.
|
||||
glob_reexport_span: Span,
|
||||
/// The local binding that shadows the glob reexport.
|
||||
private_item_span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
/// Lints that are buffered up early on in the `Session` before the
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ enum LLVMRustAttribute {
|
|||
AllocatedPointer = 38,
|
||||
AllocAlign = 39,
|
||||
#endif
|
||||
SanitizeSafeStack = 40,
|
||||
};
|
||||
|
||||
typedef struct OpaqueRustString *RustStringRef;
|
||||
|
|
|
|||
|
|
@ -234,6 +234,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
|
|||
case AllocAlign:
|
||||
return Attribute::AllocAlign;
|
||||
#endif
|
||||
case SanitizeSafeStack:
|
||||
return Attribute::SafeStack;
|
||||
}
|
||||
report_fatal_error("bad AttributeKind");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -851,7 +851,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
} else {
|
||||
tcx.arena.alloc_from_iter(lazy.decode((self, tcx)))
|
||||
};
|
||||
ty::EarlyBinder(&*output)
|
||||
ty::EarlyBinder::new(&*output)
|
||||
}
|
||||
|
||||
fn get_variant(
|
||||
|
|
|
|||
|
|
@ -1727,7 +1727,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
ty::Closure(_, substs) => {
|
||||
let constness = self.tcx.constness(def_id.to_def_id());
|
||||
self.tables.constness.set_some(def_id.to_def_id().index, constness);
|
||||
record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig()));
|
||||
record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::new(substs.as_closure().sig()));
|
||||
}
|
||||
|
||||
_ => bug!("closure that is neither generator nor closure"),
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ impl<'tcx> Body<'tcx> {
|
|||
/// Returns the return type; it always return first element from `local_decls` array.
|
||||
#[inline]
|
||||
pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
|
||||
ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty)
|
||||
ty::EarlyBinder::new(self.local_decls[RETURN_PLACE].ty)
|
||||
}
|
||||
|
||||
/// Gets the location of the terminator for the given block.
|
||||
|
|
|
|||
|
|
@ -603,7 +603,11 @@ pub enum TerminatorKind<'tcx> {
|
|||
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
|
||||
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not
|
||||
/// > consider indirect assignments.
|
||||
Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction },
|
||||
///
|
||||
/// The `replace` flag indicates whether this terminator was created as part of an assignment.
|
||||
/// This should only be used for diagnostic purposes, and does not have any operational
|
||||
/// meaning.
|
||||
Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool },
|
||||
|
||||
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
|
||||
/// the referred to function. The operand types must match the argument types of the function.
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ pub struct Terminator<'tcx> {
|
|||
pub kind: TerminatorKind<'tcx>,
|
||||
}
|
||||
|
||||
pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a;
|
||||
pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
|
||||
pub type SuccessorsMut<'a> =
|
||||
iter::Chain<std::option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
|
|||
// B C
|
||||
// | |
|
||||
// | |
|
||||
// D |
|
||||
// | D
|
||||
// \ /
|
||||
// \ /
|
||||
// E
|
||||
|
|
@ -159,26 +159,26 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
|
|||
//
|
||||
// When the first call to `traverse_successor` happens, the following happens:
|
||||
//
|
||||
// [(B, [D]), // `B` taken from the successors of `A`, pushed to the
|
||||
// // top of the stack along with the successors of `B`
|
||||
// (A, [C])]
|
||||
// [(C, [D]), // `C` taken from the successors of `A`, pushed to the
|
||||
// // top of the stack along with the successors of `C`
|
||||
// (A, [B])]
|
||||
//
|
||||
// [(D, [E]), // `D` taken from successors of `B`, pushed to stack
|
||||
// (B, []),
|
||||
// (A, [C])]
|
||||
// [(D, [E]), // `D` taken from successors of `C`, pushed to stack
|
||||
// (C, []),
|
||||
// (A, [B])]
|
||||
//
|
||||
// [(E, []), // `E` taken from successors of `D`, pushed to stack
|
||||
// (D, []),
|
||||
// (B, []),
|
||||
// (A, [C])]
|
||||
// (C, []),
|
||||
// (A, [B])]
|
||||
//
|
||||
// Now that the top of the stack has no successors we can traverse, each item will
|
||||
// be popped off during iteration until we get back to `A`. This yields [E, D, B].
|
||||
// be popped off during iteration until we get back to `A`. This yields [E, D, C].
|
||||
//
|
||||
// When we yield `B` and call `traverse_successor`, we push `C` to the stack, but
|
||||
// When we yield `C` and call `traverse_successor`, we push `B` to the stack, but
|
||||
// since we've already visited `E`, that child isn't added to the stack. The last
|
||||
// two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
|
||||
while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() {
|
||||
// two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A]
|
||||
while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next_back() {
|
||||
if self.visited.insert(bb) {
|
||||
if let Some(term) = &self.basic_blocks[bb].terminator {
|
||||
self.visit_stack.push((bb, term.successors()));
|
||||
|
|
|
|||
|
|
@ -504,6 +504,7 @@ macro_rules! make_mir_visitor {
|
|||
place,
|
||||
target: _,
|
||||
unwind: _,
|
||||
replace: _,
|
||||
} => {
|
||||
self.visit_place(
|
||||
place,
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ impl<'tcx> AdtDef<'tcx> {
|
|||
/// Due to normalization being eager, this applies even if
|
||||
/// the associated type is behind a pointer (e.g., issue #31299).
|
||||
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
|
||||
ty::EarlyBinder(tcx.adt_sized_constraint(self.did()))
|
||||
ty::EarlyBinder::new(tcx.adt_sized_constraint(self.did()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,5 +254,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBind
|
|||
"`const_param_default` expected a generic parameter with a constant"
|
||||
),
|
||||
};
|
||||
ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id))
|
||||
ty::EarlyBinder::new(Const::from_anon_const(tcx, default_def_id))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ impl<'tcx> GenericPredicates<'tcx> {
|
|||
substs: SubstsRef<'tcx>,
|
||||
) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
|
||||
{
|
||||
EarlyBinder(self.predicates).subst_iter_copied(tcx, substs)
|
||||
EarlyBinder::new(self.predicates).subst_iter_copied(tcx, substs)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, tcx))]
|
||||
|
|
@ -358,7 +358,7 @@ impl<'tcx> GenericPredicates<'tcx> {
|
|||
}
|
||||
instantiated
|
||||
.predicates
|
||||
.extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs)));
|
||||
.extend(self.predicates.iter().map(|(p, _)| EarlyBinder::new(*p).subst(tcx, substs)));
|
||||
instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
|||
fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> {
|
||||
match self {
|
||||
Self::ConstIsZero(c) => {
|
||||
let c = ty::EarlyBinder(c).subst(tcx, substs);
|
||||
let c = ty::EarlyBinder::new(c).subst(tcx, substs);
|
||||
let pred = match c.kind().try_to_target_usize(tcx) {
|
||||
Some(0) => Self::True,
|
||||
Some(1..) => Self::False,
|
||||
|
|
@ -167,7 +167,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
|||
Some(pred)
|
||||
}
|
||||
Self::GenericType(t) => {
|
||||
Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx))
|
||||
Some(ty::EarlyBinder::new(t).subst(tcx, substs).inhabited_predicate(tcx))
|
||||
}
|
||||
Self::And(&[a, b]) => match a.subst_opt(tcx, substs) {
|
||||
None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)),
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
|||
use rustc_span::{ExpnId, ExpnKind, Span};
|
||||
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
|
||||
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
||||
use rustc_type_ir::WithCachedTypeInfo;
|
||||
pub use subst::*;
|
||||
pub use vtable::*;
|
||||
|
||||
|
|
@ -145,6 +144,7 @@ mod opaque_types;
|
|||
mod parameterized;
|
||||
mod rvalue_scopes;
|
||||
mod structural_impls;
|
||||
#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
|
||||
mod sty;
|
||||
mod typeck_results;
|
||||
|
||||
|
|
@ -764,7 +764,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
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(shifted_pred).subst(tcx, trait_ref.skip_binder().substs);
|
||||
let new = EarlyBinder::new(shifted_pred).subst(tcx, trait_ref.skip_binder().substs);
|
||||
// 3) ['x] + ['b] -> ['x, 'b]
|
||||
let bound_vars =
|
||||
tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars));
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ pub trait Printer<'tcx>: Sized {
|
|||
impl_trait_ref.map(|i| i.subst(self.tcx(), substs)),
|
||||
)
|
||||
} else {
|
||||
(self_ty.0, impl_trait_ref.map(|i| i.0))
|
||||
(self_ty.subst_identity(), impl_trait_ref.map(|i| i.subst_identity()))
|
||||
};
|
||||
self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -700,7 +700,7 @@ pub trait PrettyPrinter<'tcx>:
|
|||
if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) }
|
||||
}
|
||||
}
|
||||
ty::Error(_) => p!("[type error]"),
|
||||
ty::Error(_) => p!("{{type error}}"),
|
||||
ty::Param(ref param_ty) => p!(print(param_ty)),
|
||||
ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
|
||||
ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?,
|
||||
|
|
@ -1379,8 +1379,8 @@ pub trait PrettyPrinter<'tcx>:
|
|||
},
|
||||
// FIXME(generic_const_exprs):
|
||||
// write out some legible representation of an abstract const?
|
||||
ty::ConstKind::Expr(_) => p!("[const expr]"),
|
||||
ty::ConstKind::Error(_) => p!("[const error]"),
|
||||
ty::ConstKind::Expr(_) => p!("{{const expr}}"),
|
||||
ty::ConstKind::Error(_) => p!("{{const error}}"),
|
||||
};
|
||||
Ok(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -568,7 +568,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {
|
|||
let layout = tcx.generator_layout(def_id).unwrap();
|
||||
layout.variant_fields.iter().map(move |variant| {
|
||||
variant.iter().map(move |field| {
|
||||
ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs)
|
||||
ty::EarlyBinder::new(layout.field_tys[*field].ty).subst(tcx, self.substs)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -2366,7 +2366,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
|
||||
ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)),
|
||||
|
||||
ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
|
||||
ty::Adt(def, _substs) => def.sized_constraint(tcx).skip_binder().is_empty(),
|
||||
|
||||
ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
|
||||
|
||||
|
|
|
|||
|
|
@ -538,13 +538,17 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx
|
|||
/// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[derive(Encodable, Decodable, HashStable)]
|
||||
pub struct EarlyBinder<T>(pub T);
|
||||
pub struct EarlyBinder<T>(T);
|
||||
|
||||
/// For early binders, you should first call `subst` before using any visitors.
|
||||
impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
|
||||
impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
|
||||
|
||||
impl<T> EarlyBinder<T> {
|
||||
pub fn new(inner: T) -> EarlyBinder<T> {
|
||||
EarlyBinder(inner)
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> EarlyBinder<&T> {
|
||||
EarlyBinder(&self.0)
|
||||
}
|
||||
|
|
@ -582,6 +586,9 @@ impl<T> EarlyBinder<T> {
|
|||
/// arguments of an `FnSig`). Otherwise, consider using
|
||||
/// [`subst_identity`](EarlyBinder::subst_identity).
|
||||
///
|
||||
/// To skip the binder on `x: &EarlyBinder<T>` to obtain `&T`, leverage
|
||||
/// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`.
|
||||
///
|
||||
/// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
|
||||
/// the analogous operation on [`super::Binder`].
|
||||
pub fn skip_binder(self) -> T {
|
||||
|
|
|
|||
|
|
@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
.as_ref()
|
||||
.map_or_else(|| [].iter(), |l| l.field_tys.iter())
|
||||
.filter(|decl| !decl.ignore_for_traits)
|
||||
.map(|decl| ty::EarlyBinder(decl.ty))
|
||||
.map(|decl| ty::EarlyBinder::new(decl.ty))
|
||||
}
|
||||
|
||||
/// Normalizes all opaque types in the given value, replacing them
|
||||
|
|
|
|||
|
|
@ -96,13 +96,13 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
|
|||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
|
||||
ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle))
|
||||
ty::EarlyBinder::new(Ty::from_cycle_error(tcx, cycle))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
|
||||
ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle))
|
||||
ty::EarlyBinder::new(ty::Binder::from_cycle_error(tcx, cycle))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||
place: self.parse_place(args[0])?,
|
||||
target: self.parse_block(args[1])?,
|
||||
unwind: UnwindAction::Continue,
|
||||
replace: false,
|
||||
})
|
||||
},
|
||||
@call("mir_call", args) => {
|
||||
|
|
|
|||
|
|
@ -725,6 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
place: to_drop,
|
||||
target: success,
|
||||
unwind: UnwindAction::Continue,
|
||||
replace: false,
|
||||
},
|
||||
);
|
||||
this.diverge_from(block);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ use rustc_middle::middle::region;
|
|||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::{Expr, LintLevel};
|
||||
|
||||
use rustc_span::{DesugaringKind, Span, DUMMY_SP};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Scopes<'tcx> {
|
||||
|
|
@ -371,6 +371,7 @@ impl DropTree {
|
|||
// The caller will handle this if needed.
|
||||
unwind: UnwindAction::Terminate,
|
||||
place: drop_data.0.local.into(),
|
||||
replace: false,
|
||||
};
|
||||
cfg.terminate(block, drop_data.0.source_info, terminator);
|
||||
}
|
||||
|
|
@ -1128,9 +1129,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
place: Place<'tcx>,
|
||||
value: Rvalue<'tcx>,
|
||||
) -> BlockAnd<()> {
|
||||
let span = self.tcx.with_stable_hashing_context(|hcx| {
|
||||
span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx)
|
||||
});
|
||||
let source_info = self.source_info(span);
|
||||
|
||||
// create the new block for the assignment
|
||||
|
|
@ -1148,6 +1146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
place,
|
||||
target: assign,
|
||||
unwind: UnwindAction::Cleanup(assign_unwind),
|
||||
replace: true,
|
||||
},
|
||||
);
|
||||
self.diverge_from(block);
|
||||
|
|
@ -1261,6 +1260,7 @@ fn build_scope_drops<'tcx>(
|
|||
place: local.into(),
|
||||
target: next,
|
||||
unwind: UnwindAction::Continue,
|
||||
replace: false,
|
||||
},
|
||||
);
|
||||
block = next;
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ where
|
|||
place: self.place,
|
||||
target: self.succ,
|
||||
unwind: self.unwind.into_action(),
|
||||
replace: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -719,6 +720,7 @@ where
|
|||
place: tcx.mk_place_deref(ptr),
|
||||
target: loop_block,
|
||||
unwind: unwind.into_action(),
|
||||
replace: false,
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -963,8 +965,12 @@ where
|
|||
}
|
||||
|
||||
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
|
||||
let block =
|
||||
TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() };
|
||||
let block = TerminatorKind::Drop {
|
||||
place: self.place,
|
||||
target,
|
||||
unwind: unwind.into_action(),
|
||||
replace: false,
|
||||
};
|
||||
self.new_block(unwind, block)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -479,7 +479,7 @@ impl Direction for Forward {
|
|||
Goto { target } => propagate(target, exit_state),
|
||||
|
||||
Assert { target, unwind, expected: _, msg: _, cond: _ }
|
||||
| Drop { target, unwind, place: _ }
|
||||
| Drop { target, unwind, place: _, replace: _ }
|
||||
| FalseUnwind { real_target: target, unwind } => {
|
||||
if let UnwindAction::Cleanup(unwind) = unwind {
|
||||
propagate(unwind, exit_state);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ fn add_move_for_packed_drop<'tcx>(
|
|||
is_cleanup: bool,
|
||||
) {
|
||||
debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
|
||||
let TerminatorKind::Drop { ref place, target, unwind } = terminator.kind else {
|
||||
let TerminatorKind::Drop { ref place, target, unwind, replace } = terminator.kind else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
|
|
@ -98,6 +98,11 @@ fn add_move_for_packed_drop<'tcx>(
|
|||
patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
|
||||
patch.patch_terminator(
|
||||
loc.block,
|
||||
TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind },
|
||||
TerminatorKind::Drop {
|
||||
place: Place::from(temp),
|
||||
target: storage_dead_block,
|
||||
unwind,
|
||||
replace,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,14 @@ struct PointerFinder<'tcx, 'a> {
|
|||
}
|
||||
|
||||
impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> {
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
if let Rvalue::AddressOf(..) = rvalue {
|
||||
// Ignore dereferences inside of an AddressOf
|
||||
return;
|
||||
}
|
||||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
|
||||
if let PlaceContext::NonUse(_) = context {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_mir_dataflow::un_derefer::UnDerefer;
|
|||
use rustc_mir_dataflow::MoveDataParamEnv;
|
||||
use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits};
|
||||
use rustc_mir_dataflow::{Analysis, ResultsCursor};
|
||||
use rustc_span::{DesugaringKind, Span};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
use std::fmt;
|
||||
|
||||
|
|
@ -401,7 +401,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
let terminator = data.terminator();
|
||||
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { mut place, target, unwind } => {
|
||||
TerminatorKind::Drop { mut place, target, unwind, replace } => {
|
||||
if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
|
||||
place = new_place;
|
||||
}
|
||||
|
|
@ -434,10 +434,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
)
|
||||
}
|
||||
LookupResult::Parent(..) => {
|
||||
if !matches!(
|
||||
terminator.source_info.span.desugaring_kind(),
|
||||
Some(DesugaringKind::Replace),
|
||||
) {
|
||||
if !replace {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
terminator.source_info.span,
|
||||
format!("drop of untracked value {:?}", bb),
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
|
|||
// If the inner type matches the type bound by `Pointer`
|
||||
if inner_ty == bound_ty {
|
||||
// Do a substitution using the parameters from the callsite
|
||||
let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref);
|
||||
let subst_ty = EarlyBinder::new(inner_ty).subst(self.tcx, substs_ref);
|
||||
if let Some((fn_id, fn_substs)) =
|
||||
FunctionItemRefChecker::is_fn_ref(subst_ty)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1045,7 +1045,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
|
||||
for (block, block_data) in body.basic_blocks.iter_enumerated() {
|
||||
let (target, unwind, source_info) = match block_data.terminator() {
|
||||
Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
|
||||
Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Drop { place, target, unwind, replace: _ },
|
||||
} => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if local == SELF_ARG {
|
||||
(target, unwind, source_info)
|
||||
|
|
@ -1304,6 +1307,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
|
|||
place: Place::from(SELF_ARG),
|
||||
target: return_block,
|
||||
unwind: UnwindAction::Continue,
|
||||
replace: false,
|
||||
};
|
||||
let source_info = SourceInfo::outermost(body.span);
|
||||
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ impl<'tcx> Inliner<'tcx> {
|
|||
let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
ty::EarlyBinder(callee_body.clone()),
|
||||
ty::EarlyBinder::new(callee_body.clone()),
|
||||
) else {
|
||||
return Err("failed to normalize callee body");
|
||||
};
|
||||
|
|
@ -449,16 +449,16 @@ impl<'tcx> Inliner<'tcx> {
|
|||
checker.visit_basic_block_data(bb, blk);
|
||||
|
||||
let term = blk.terminator();
|
||||
if let TerminatorKind::Drop { ref place, target, unwind } = term.kind {
|
||||
if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind {
|
||||
work_list.push(target);
|
||||
|
||||
// If the place doesn't actually need dropping, treat it like a regular goto.
|
||||
let ty = callsite
|
||||
.callee
|
||||
.subst_mir(self.tcx, ty::EarlyBinder(&place.ty(callee_body, tcx).ty));
|
||||
.subst_mir(self.tcx, ty::EarlyBinder::new(&place.ty(callee_body, tcx).ty));
|
||||
if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind {
|
||||
work_list.push(unwind);
|
||||
}
|
||||
work_list.push(unwind);
|
||||
}
|
||||
} else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
|
||||
&& matches!(term.kind, TerminatorKind::InlineAsm { .. })
|
||||
{
|
||||
|
|
@ -790,7 +790,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
|
|||
// If the place doesn't actually need dropping, treat it like a regular goto.
|
||||
let ty = self
|
||||
.instance
|
||||
.subst_mir(tcx, ty::EarlyBinder(&place.ty(self.callee_body, tcx).ty));
|
||||
.subst_mir(tcx, ty::EarlyBinder::new(&place.ty(self.callee_body, tcx).ty));
|
||||
if ty.needs_drop(tcx, self.param_env) {
|
||||
self.cost += CALL_PENALTY;
|
||||
if let UnwindAction::Cleanup(_) = unwind {
|
||||
|
|
@ -801,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
|
||||
let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder(&f.literal.ty()));
|
||||
let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::new(&f.literal.ty()));
|
||||
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
|
||||
// Don't give intrinsics the extra penalty for calls
|
||||
INSTR_COST
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
|
|||
let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(
|
||||
tcx,
|
||||
param_env,
|
||||
ty::EarlyBinder(substs),
|
||||
ty::EarlyBinder::new(substs),
|
||||
) else {
|
||||
trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping");
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(is_sorted)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(min_specialization)]
|
||||
|
|
@ -84,6 +85,7 @@ mod match_branches;
|
|||
mod multiple_return_terminators;
|
||||
mod normalize_array_len;
|
||||
mod nrvo;
|
||||
mod prettify;
|
||||
mod ref_prop;
|
||||
mod remove_noop_landing_pads;
|
||||
mod remove_storage_markers;
|
||||
|
|
@ -581,6 +583,9 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
&large_enums::EnumSizeOpt { discrepancy: 128 },
|
||||
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
|
||||
&add_call_guards::CriticalCallEdges,
|
||||
// Cleanup for human readability, off by default.
|
||||
&prettify::ReorderBasicBlocks,
|
||||
&prettify::ReorderLocals,
|
||||
// Dump the end result for testing and debugging purposes.
|
||||
&dump_mir::Marker("PreCodegen"),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ pub struct MatchBranchSimplification;
|
|||
|
||||
impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 3
|
||||
sess.mir_opt_level() >= 1
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
|
|
@ -62,7 +62,12 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||
..
|
||||
} if targets.iter().len() == 1 => {
|
||||
let (value, target) = targets.iter().next().unwrap();
|
||||
if target == targets.otherwise() {
|
||||
// We require that this block and the two possible target blocks all be
|
||||
// distinct.
|
||||
if target == targets.otherwise()
|
||||
|| bb_idx == target
|
||||
|| bb_idx == targets.otherwise()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
(discr, value, target, targets.otherwise())
|
||||
|
|
|
|||
150
compiler/rustc_mir_transform/src/prettify.rs
Normal file
150
compiler/rustc_mir_transform/src/prettify.rs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
//! These two passes provide no value to the compiler, so are off at every level.
|
||||
//!
|
||||
//! However, they can be enabled on the command line
|
||||
//! (`-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals`)
|
||||
//! to make the MIR easier to read for humans.
|
||||
|
||||
use crate::MirPass;
|
||||
use rustc_index::{bit_set::BitSet, IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
|
||||
/// Rearranges the basic blocks into a *reverse post-order*.
|
||||
///
|
||||
/// Thus after this pass, all the successors of a block are later than it in the
|
||||
/// `IndexVec`, unless that successor is a back-edge (such as from a loop).
|
||||
pub struct ReorderBasicBlocks;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
|
||||
fn is_enabled(&self, _session: &Session) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let rpo: IndexVec<BasicBlock, BasicBlock> =
|
||||
body.basic_blocks.postorder().iter().copied().rev().collect();
|
||||
if rpo.iter().is_sorted() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut updater = BasicBlockUpdater { map: rpo.invert_bijective_mapping(), tcx };
|
||||
debug_assert_eq!(updater.map[START_BLOCK], START_BLOCK);
|
||||
updater.visit_body(body);
|
||||
|
||||
permute(body.basic_blocks.as_mut(), &updater.map);
|
||||
}
|
||||
}
|
||||
|
||||
/// Rearranges the locals into *use* order.
|
||||
///
|
||||
/// Thus after this pass, a local with a smaller [`Location`] where it was first
|
||||
/// assigned or referenced will have a smaller number.
|
||||
///
|
||||
/// (Does not reorder arguments nor the [`RETURN_PLACE`].)
|
||||
pub struct ReorderLocals;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ReorderLocals {
|
||||
fn is_enabled(&self, _session: &Session) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let mut finder =
|
||||
LocalFinder { map: IndexVec::new(), seen: BitSet::new_empty(body.local_decls.len()) };
|
||||
|
||||
// We can't reorder the return place or the arguments
|
||||
for local in (0..=body.arg_count).map(Local::from_usize) {
|
||||
finder.track(local);
|
||||
}
|
||||
|
||||
for (bb, bbd) in body.basic_blocks.iter_enumerated() {
|
||||
finder.visit_basic_block_data(bb, bbd);
|
||||
}
|
||||
|
||||
// track everything in case there are some locals that we never saw,
|
||||
// such as in non-block things like debug info or in non-uses.
|
||||
for local in body.local_decls.indices() {
|
||||
finder.track(local);
|
||||
}
|
||||
|
||||
if finder.map.iter().is_sorted() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut updater = LocalUpdater { map: finder.map.invert_bijective_mapping(), tcx };
|
||||
|
||||
for local in (0..=body.arg_count).map(Local::from_usize) {
|
||||
debug_assert_eq!(updater.map[local], local);
|
||||
}
|
||||
|
||||
updater.visit_body_preserves_cfg(body);
|
||||
|
||||
permute(&mut body.local_decls, &updater.map);
|
||||
}
|
||||
}
|
||||
|
||||
fn permute<I: rustc_index::Idx + Ord, T>(data: &mut IndexVec<I, T>, map: &IndexSlice<I, I>) {
|
||||
// FIXME: It would be nice to have a less-awkward way to apply permutations,
|
||||
// but I don't know one that exists. `sort_by_cached_key` has logic for it
|
||||
// internally, but not in a way that we're allowed to use here.
|
||||
let mut enumerated: Vec<_> = std::mem::take(data).into_iter_enumerated().collect();
|
||||
enumerated.sort_by_key(|p| map[p.0]);
|
||||
*data = enumerated.into_iter().map(|p| p.1).collect();
|
||||
}
|
||||
|
||||
struct BasicBlockUpdater<'tcx> {
|
||||
map: IndexVec<BasicBlock, BasicBlock>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for BasicBlockUpdater<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, _location: Location) {
|
||||
for succ in terminator.successors_mut() {
|
||||
*succ = self.map[*succ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalFinder {
|
||||
map: IndexVec<Local, Local>,
|
||||
seen: BitSet<Local>,
|
||||
}
|
||||
|
||||
impl LocalFinder {
|
||||
fn track(&mut self, l: Local) {
|
||||
if self.seen.insert(l) {
|
||||
self.map.push(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for LocalFinder {
|
||||
fn visit_local(&mut self, l: Local, context: PlaceContext, _location: Location) {
|
||||
// Exclude non-uses to keep `StorageLive` from controlling where we put
|
||||
// a `Local`, since it might not actually be assigned until much later.
|
||||
if context.is_use() {
|
||||
self.track(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalUpdater<'tcx> {
|
||||
pub map: IndexVec<Local, Local>,
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
|
||||
*l = self.map[*l];
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
|
|||
// of this function. Is this intentional?
|
||||
if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) {
|
||||
let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap();
|
||||
let body = EarlyBinder(body.clone()).subst(tcx, substs);
|
||||
let body = EarlyBinder::new(body.clone()).subst(tcx, substs);
|
||||
debug!("make_shim({:?}) = {:?}", instance, body);
|
||||
return body;
|
||||
}
|
||||
|
|
@ -544,6 +544,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
|||
place: dest_field,
|
||||
target: unwind,
|
||||
unwind: UnwindAction::Terminate,
|
||||
replace: false,
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
|
@ -643,8 +644,11 @@ fn build_call_shim<'tcx>(
|
|||
let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig));
|
||||
|
||||
assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
|
||||
let mut sig =
|
||||
if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 };
|
||||
let mut sig = if let Some(sig_substs) = sig_substs {
|
||||
sig.subst(tcx, &sig_substs)
|
||||
} else {
|
||||
sig.skip_binder()
|
||||
};
|
||||
|
||||
if let CallKind::Indirect(fnty) = call_kind {
|
||||
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
|
||||
|
|
@ -800,6 +804,7 @@ fn build_call_shim<'tcx>(
|
|||
place: rcvr_place(),
|
||||
target: BasicBlock::new(2),
|
||||
unwind: UnwindAction::Continue,
|
||||
replace: false,
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
|
@ -815,6 +820,7 @@ fn build_call_shim<'tcx>(
|
|||
place: rcvr_place(),
|
||||
target: BasicBlock::new(4),
|
||||
unwind: UnwindAction::Terminate,
|
||||
replace: false,
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
|
|||
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||
self.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
ty::EarlyBinder(value),
|
||||
ty::EarlyBinder::new(value),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
|
|||
let before_feature_tys = tcx.subst_and_normalize_erasing_regions(
|
||||
closure_instance.substs,
|
||||
param_env,
|
||||
ty::EarlyBinder(before_feature_tys),
|
||||
ty::EarlyBinder::new(before_feature_tys),
|
||||
);
|
||||
let after_feature_tys = tcx.subst_and_normalize_erasing_regions(
|
||||
closure_instance.substs,
|
||||
param_env,
|
||||
ty::EarlyBinder(after_feature_tys),
|
||||
ty::EarlyBinder::new(after_feature_tys),
|
||||
);
|
||||
|
||||
let new_size = tcx
|
||||
|
|
|
|||
|
|
@ -536,7 +536,9 @@ impl<'a> Parser<'a> {
|
|||
} else if inedible.contains(&self.token.kind) {
|
||||
// leave it in the input
|
||||
Ok(false)
|
||||
} else if self.last_unexpected_token_span == Some(self.token.span) {
|
||||
} else if self.token.kind != token::Eof
|
||||
&& self.last_unexpected_token_span == Some(self.token.span)
|
||||
{
|
||||
FatalError.raise();
|
||||
} else {
|
||||
self.expected_one_of_not_found(edible, inedible)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ use rustc_middle::metadata::Reexport;
|
|||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::lint::builtin::{
|
||||
AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS,
|
||||
AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||
UNUSED_IMPORTS,
|
||||
};
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
|
@ -526,31 +527,71 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_reexport_ambiguities(
|
||||
pub(crate) fn check_hidden_glob_reexports(
|
||||
&mut self,
|
||||
exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>,
|
||||
) {
|
||||
for module in self.arenas.local_modules().iter() {
|
||||
module.for_each_child(self, |this, ident, ns, binding| {
|
||||
if let NameBindingKind::Import { import, .. } = binding.kind
|
||||
&& let Some((amb_binding, _)) = binding.ambiguity
|
||||
&& binding.res() != Res::Err
|
||||
&& exported_ambiguities.contains(&Interned::new_unchecked(binding))
|
||||
{
|
||||
this.lint_buffer.buffer_lint_with_diagnostic(
|
||||
AMBIGUOUS_GLOB_REEXPORTS,
|
||||
import.root_id,
|
||||
import.root_span,
|
||||
"ambiguous glob re-exports",
|
||||
BuiltinLintDiagnostics::AmbiguousGlobReexports {
|
||||
name: ident.to_string(),
|
||||
namespace: ns.descr().to_string(),
|
||||
first_reexport_span: import.root_span,
|
||||
duplicate_reexport_span: amb_binding.span,
|
||||
},
|
||||
);
|
||||
for (key, resolution) in self.resolutions(module).borrow().iter() {
|
||||
let resolution = resolution.borrow();
|
||||
|
||||
if let Some(binding) = resolution.binding {
|
||||
if let NameBindingKind::Import { import, .. } = binding.kind
|
||||
&& let Some((amb_binding, _)) = binding.ambiguity
|
||||
&& binding.res() != Res::Err
|
||||
&& exported_ambiguities.contains(&Interned::new_unchecked(binding))
|
||||
{
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
AMBIGUOUS_GLOB_REEXPORTS,
|
||||
import.root_id,
|
||||
import.root_span,
|
||||
"ambiguous glob re-exports",
|
||||
BuiltinLintDiagnostics::AmbiguousGlobReexports {
|
||||
name: key.ident.to_string(),
|
||||
namespace: key.ns.descr().to_string(),
|
||||
first_reexport_span: import.root_span,
|
||||
duplicate_reexport_span: amb_binding.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(glob_binding) = resolution.shadowed_glob {
|
||||
let binding_id = match binding.kind {
|
||||
NameBindingKind::Res(res) => {
|
||||
Some(self.def_id_to_node_id[res.def_id().expect_local()])
|
||||
}
|
||||
NameBindingKind::Module(module) => {
|
||||
Some(self.def_id_to_node_id[module.def_id().expect_local()])
|
||||
}
|
||||
NameBindingKind::Import { import, .. } => import.id(),
|
||||
};
|
||||
|
||||
if binding.res() != Res::Err
|
||||
&& glob_binding.res() != Res::Err
|
||||
&& let NameBindingKind::Import { import: glob_import, .. } = glob_binding.kind
|
||||
&& let Some(binding_id) = binding_id
|
||||
&& let Some(glob_import_id) = glob_import.id()
|
||||
&& let glob_import_def_id = self.local_def_id(glob_import_id)
|
||||
&& self.effective_visibilities.is_exported(glob_import_def_id)
|
||||
&& glob_binding.vis.is_public()
|
||||
&& !binding.vis.is_public()
|
||||
{
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
HIDDEN_GLOB_REEXPORTS,
|
||||
binding_id,
|
||||
binding.span,
|
||||
"private item shadows public glob re-export",
|
||||
BuiltinLintDiagnostics::HiddenGlobReexports {
|
||||
name: key.ident.name.to_string(),
|
||||
namespace: key.ns.descr().to_owned(),
|
||||
glob_reexport_span: glob_binding.span,
|
||||
private_item_span: binding.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1496,8 +1496,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || {
|
||||
EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
|
||||
});
|
||||
self.tcx.sess.time("check_reexport_ambiguities", || {
|
||||
self.check_reexport_ambiguities(exported_ambiguities)
|
||||
self.tcx.sess.time("check_hidden_glob_reexports", || {
|
||||
self.check_hidden_glob_reexports(exported_ambiguities)
|
||||
});
|
||||
self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
|
||||
self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ mod desc {
|
|||
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
||||
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
|
||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
|
||||
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
||||
pub const parse_cfguard: &str =
|
||||
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
||||
|
|
@ -694,6 +694,7 @@ mod parse {
|
|||
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
|
||||
"thread" => SanitizerSet::THREAD,
|
||||
"hwaddress" => SanitizerSet::HWADDRESS,
|
||||
"safestack" => SanitizerSet::SAFESTACK,
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ fn rustc_terminator_to_terminator(
|
|||
Terminate => Terminator::Abort,
|
||||
Return => Terminator::Return,
|
||||
Unreachable => Terminator::Unreachable,
|
||||
Drop { place, target, unwind } => Terminator::Drop {
|
||||
Drop { place, target, unwind, replace: _ } => Terminator::Drop {
|
||||
place: rustc_place_to_place(place),
|
||||
target: target.as_usize(),
|
||||
unwind: rustc_unwind_to_unwind(unwind),
|
||||
|
|
|
|||
|
|
@ -1147,7 +1147,6 @@ pub enum DesugaringKind {
|
|||
Await,
|
||||
ForLoop,
|
||||
WhileLoop,
|
||||
Replace,
|
||||
}
|
||||
|
||||
impl DesugaringKind {
|
||||
|
|
@ -1163,7 +1162,6 @@ impl DesugaringKind {
|
|||
DesugaringKind::OpaqueTy => "`impl Trait`",
|
||||
DesugaringKind::ForLoop => "`for` loop",
|
||||
DesugaringKind::WhileLoop => "`while` loop",
|
||||
DesugaringKind::Replace => "drop and replace",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
|
|||
|
||||
let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id);
|
||||
if !substs.is_empty() {
|
||||
param_env = EarlyBinder(param_env).subst(self.tcx, substs);
|
||||
param_env = EarlyBinder::new(param_env).subst(self.tcx, substs);
|
||||
}
|
||||
|
||||
match &mut impl_trait_ref {
|
||||
|
|
|
|||
|
|
@ -815,6 +815,7 @@ bitflags::bitflags! {
|
|||
const SHADOWCALLSTACK = 1 << 7;
|
||||
const KCFI = 1 << 8;
|
||||
const KERNELADDRESS = 1 << 9;
|
||||
const SAFESTACK = 1 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -831,6 +832,7 @@ impl SanitizerSet {
|
|||
SanitizerSet::LEAK => "leak",
|
||||
SanitizerSet::MEMORY => "memory",
|
||||
SanitizerSet::MEMTAG => "memtag",
|
||||
SanitizerSet::SAFESTACK => "safestack",
|
||||
SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
|
||||
SanitizerSet::THREAD => "thread",
|
||||
SanitizerSet::HWADDRESS => "hwaddress",
|
||||
|
|
@ -871,6 +873,7 @@ impl IntoIterator for SanitizerSet {
|
|||
SanitizerSet::THREAD,
|
||||
SanitizerSet::HWADDRESS,
|
||||
SanitizerSet::KERNELADDRESS,
|
||||
SanitizerSet::SAFESTACK,
|
||||
]
|
||||
.iter()
|
||||
.copied()
|
||||
|
|
@ -2364,6 +2367,7 @@ impl Target {
|
|||
Some("leak") => SanitizerSet::LEAK,
|
||||
Some("memory") => SanitizerSet::MEMORY,
|
||||
Some("memtag") => SanitizerSet::MEMTAG,
|
||||
Some("safestack") => SanitizerSet::SAFESTACK,
|
||||
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
|
||||
Some("thread") => SanitizerSet::THREAD,
|
||||
Some("hwaddress") => SanitizerSet::HWADDRESS,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub fn target() -> Target {
|
|||
| SanitizerSet::CFI
|
||||
| SanitizerSet::LEAK
|
||||
| SanitizerSet::MEMORY
|
||||
| SanitizerSet::SAFESTACK
|
||||
| SanitizerSet::THREAD;
|
||||
base.supports_xray = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -148,11 +148,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
|||
|
||||
ty::Adt(def, substs) => {
|
||||
let sized_crit = def.sized_constraint(ecx.tcx());
|
||||
Ok(sized_crit
|
||||
.0
|
||||
.iter()
|
||||
.map(|ty| sized_crit.rebind(*ty).subst(ecx.tcx(), substs))
|
||||
.collect())
|
||||
Ok(sized_crit.subst_iter_copied(ecx.tcx(), substs).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,13 +231,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
|
||||
let mut candidates = Vec::new();
|
||||
// LHS normalizes-to RHS
|
||||
candidates.extend(
|
||||
evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(),
|
||||
);
|
||||
candidates.extend(evaluate_normalizes_to(
|
||||
self,
|
||||
alias_lhs,
|
||||
rhs,
|
||||
direction,
|
||||
Invert::No,
|
||||
));
|
||||
// RHS normalizes-to RHS
|
||||
candidates.extend(
|
||||
evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(),
|
||||
);
|
||||
candidates.extend(evaluate_normalizes_to(
|
||||
self,
|
||||
alias_rhs,
|
||||
lhs,
|
||||
direction,
|
||||
Invert::Yes,
|
||||
));
|
||||
// Relate via substs
|
||||
let subst_relate_response = self.probe(|ecx| {
|
||||
let span = tracing::span!(
|
||||
|
|
@ -265,10 +273,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
|
||||
if let Some(merged) = self.try_merge_responses(&candidates) {
|
||||
Ok(merged)
|
||||
} else if let Ok(subst_relate_response) = subst_relate_response {
|
||||
Ok(subst_relate_response)
|
||||
} else {
|
||||
self.flounder(&candidates)
|
||||
// When relating two aliases and we have ambiguity, we prefer
|
||||
// relating the generic arguments of the aliases over normalizing
|
||||
// them. This is necessary for inference during typeck.
|
||||
//
|
||||
// As this is incomplete, we must not do so during coherence.
|
||||
match (self.solver_mode(), subst_relate_response) {
|
||||
(SolverMode::Normal, Ok(response)) => Ok(response),
|
||||
(SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => {
|
||||
self.flounder(&candidates)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||
#[inline]
|
||||
fn register_predicate_obligation(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -14,10 +14,12 @@ mod object_safety;
|
|||
pub mod outlives_bounds;
|
||||
mod project;
|
||||
pub mod query;
|
||||
#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
|
||||
mod select;
|
||||
mod specialize;
|
||||
mod structural_match;
|
||||
mod structural_normalize;
|
||||
#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
|
||||
mod util;
|
||||
mod vtable;
|
||||
pub mod wf;
|
||||
|
|
@ -485,7 +487,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
|
|||
tcx,
|
||||
ObligationCause::dummy_with_span(*span),
|
||||
param_env,
|
||||
ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
|
||||
ty::EarlyBinder::new(*pred).subst(tcx, impl_trait_ref.substs),
|
||||
)
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ fn receiver_for_self_ty<'tcx>(
|
|||
if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
|
||||
});
|
||||
|
||||
let result = EarlyBinder(receiver_ty).subst(tcx, substs);
|
||||
let result = EarlyBinder::new(receiver_ty).subst(tcx, substs);
|
||||
debug!(
|
||||
"receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
|
||||
receiver_ty, self_ty, method_def_id, result
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::infer::InferCtxt;
|
||||
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
|
||||
use crate::traits::{ObligationCause, ObligationCtxt};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
|
||||
use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
||||
|
|
@ -68,20 +68,29 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
|||
return vec![];
|
||||
}
|
||||
|
||||
let span = self.tcx.def_span(body_id);
|
||||
let result: Result<_, ErrorGuaranteed> = param_env
|
||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||
.fully_perform(self, span);
|
||||
let result = match result {
|
||||
Ok(r) => r,
|
||||
Err(_) => {
|
||||
return vec![];
|
||||
}
|
||||
let mut canonical_var_values = OriginalQueryValues::default();
|
||||
let canonical_ty =
|
||||
self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values);
|
||||
let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
let TypeOpOutput { output, constraints, .. } = result;
|
||||
let mut constraints = QueryRegionConstraints::default();
|
||||
let Ok(InferOk { value, obligations }) = self
|
||||
.instantiate_nll_query_response_and_region_obligations(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
&canonical_var_values,
|
||||
canonical_result,
|
||||
&mut constraints,
|
||||
) else {
|
||||
return vec![];
|
||||
};
|
||||
assert_eq!(&obligations, &[]);
|
||||
|
||||
if !constraints.is_empty() {
|
||||
let span = self.tcx.def_span(body_id);
|
||||
|
||||
if let Some(constraints) = constraints {
|
||||
debug!(?constraints);
|
||||
if !constraints.member_constraints.is_empty() {
|
||||
span_bug!(span, "{:#?}", constraints.member_constraints);
|
||||
|
|
@ -108,7 +117,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
output
|
||||
value
|
||||
}
|
||||
|
||||
fn implied_bounds_tys(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use crate::traits::query::normalize::QueryNormalizeExt;
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
|
||||
|
||||
pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
|
||||
use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_span::source_map::{Span, DUMMY_SP};
|
||||
|
||||
/// This returns true if the type `ty` is "trivial" for
|
||||
/// dropck-outlives -- that is, if it doesn't require any types to
|
||||
|
|
@ -71,3 +76,263 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
| ty::Generator(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_dropck_outlives_inner<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
let ParamEnvAnd { param_env, value: for_ty } = goal;
|
||||
|
||||
let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
|
||||
|
||||
// A stack of types left to process. Each round, we pop
|
||||
// something from the stack and invoke
|
||||
// `dtorck_constraint_for_ty_inner`. This may produce new types that
|
||||
// have to be pushed on the stack. This continues until we have explored
|
||||
// all the reachable types from the type `for_ty`.
|
||||
//
|
||||
// Example: Imagine that we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// struct A {
|
||||
// value: B,
|
||||
// children: Vec<A>,
|
||||
// }
|
||||
//
|
||||
// struct B {
|
||||
// value: u32
|
||||
// }
|
||||
//
|
||||
// fn f() {
|
||||
// let a: A = ...;
|
||||
// ..
|
||||
// } // here, `a` is dropped
|
||||
// ```
|
||||
//
|
||||
// at the point where `a` is dropped, we need to figure out
|
||||
// which types inside of `a` contain region data that may be
|
||||
// accessed by any destructors in `a`. We begin by pushing `A`
|
||||
// onto the stack, as that is the type of `a`. We will then
|
||||
// invoke `dtorck_constraint_for_ty_inner` which will expand `A`
|
||||
// into the types of its fields `(B, Vec<A>)`. These will get
|
||||
// pushed onto the stack. Eventually, expanding `Vec<A>` will
|
||||
// lead to us trying to push `A` a second time -- to prevent
|
||||
// infinite recursion, we notice that `A` was already pushed
|
||||
// once and stop.
|
||||
let mut ty_stack = vec![(for_ty, 0)];
|
||||
|
||||
// Set used to detect infinite recursion.
|
||||
let mut ty_set = FxHashSet::default();
|
||||
|
||||
let cause = ObligationCause::dummy();
|
||||
let mut constraints = DropckConstraint::empty();
|
||||
while let Some((ty, depth)) = ty_stack.pop() {
|
||||
debug!(
|
||||
"{} kinds, {} overflows, {} ty_stack",
|
||||
result.kinds.len(),
|
||||
result.overflows.len(),
|
||||
ty_stack.len()
|
||||
);
|
||||
dtorck_constraint_for_ty_inner(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
|
||||
|
||||
// "outlives" represent types/regions that may be touched
|
||||
// by a destructor.
|
||||
result.kinds.append(&mut constraints.outlives);
|
||||
result.overflows.append(&mut constraints.overflows);
|
||||
|
||||
// If we have even one overflow, we should stop trying to evaluate further --
|
||||
// chances are, the subsequent overflows for this evaluation won't provide useful
|
||||
// information and will just decrease the speed at which we can emit these errors
|
||||
// (since we'll be printing for just that much longer for the often enormous types
|
||||
// that result here).
|
||||
if !result.overflows.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
// dtorck types are "types that will get dropped but which
|
||||
// do not themselves define a destructor", more or less. We have
|
||||
// to push them onto the stack to be expanded.
|
||||
for ty in constraints.dtorck_types.drain(..) {
|
||||
let Normalized { value: ty, obligations } =
|
||||
ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
|
||||
ocx.register_obligations(obligations);
|
||||
|
||||
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
|
||||
|
||||
match ty.kind() {
|
||||
// All parameters live for the duration of the
|
||||
// function.
|
||||
ty::Param(..) => {}
|
||||
|
||||
// A projection that we couldn't resolve - it
|
||||
// might have a destructor.
|
||||
ty::Alias(..) => {
|
||||
result.kinds.push(ty.into());
|
||||
}
|
||||
|
||||
_ => {
|
||||
if ty_set.insert(ty) {
|
||||
ty_stack.push((ty, depth + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("dropck_outlives: result = {:#?}", result);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Returns a set of constraints that needs to be satisfied in
|
||||
/// order for `ty` to be valid for destruction.
|
||||
pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
for_ty: Ty<'tcx>,
|
||||
depth: usize,
|
||||
ty: Ty<'tcx>,
|
||||
constraints: &mut DropckConstraint<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
|
||||
|
||||
if !tcx.recursion_limit().value_within_limit(depth) {
|
||||
constraints.overflows.push(ty);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if trivial_dropck_outlives(tcx, ty) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Str
|
||||
| ty::Never
|
||||
| ty::Foreign(..)
|
||||
| ty::RawPtr(..)
|
||||
| ty::Ref(..)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(_)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..) => {
|
||||
// these types never have a destructor
|
||||
}
|
||||
|
||||
ty::Array(ety, _) | ty::Slice(ety) => {
|
||||
// single-element containers, behave like their element
|
||||
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints)
|
||||
})?;
|
||||
}
|
||||
|
||||
ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
for ty in tys.iter() {
|
||||
dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
|
||||
}
|
||||
Ok::<_, NoSolution>(())
|
||||
})?,
|
||||
|
||||
ty::Closure(_, substs) => {
|
||||
if !substs.as_closure().is_valid() {
|
||||
// By the time this code runs, all type variables ought to
|
||||
// be fully resolved.
|
||||
|
||||
tcx.sess.delay_span_bug(
|
||||
span,
|
||||
format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
|
||||
);
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
for ty in substs.as_closure().upvar_tys() {
|
||||
dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
|
||||
}
|
||||
Ok::<_, NoSolution>(())
|
||||
})?
|
||||
}
|
||||
|
||||
ty::Generator(_, substs, _movability) => {
|
||||
// rust-lang/rust#49918: types can be constructed, stored
|
||||
// in the interior, and sit idle when generator yields
|
||||
// (and is subsequently dropped).
|
||||
//
|
||||
// It would be nice to descend into interior of a
|
||||
// generator to determine what effects dropping it might
|
||||
// have (by looking at any drop effects associated with
|
||||
// its interior).
|
||||
//
|
||||
// However, the interior's representation uses things like
|
||||
// GeneratorWitness that explicitly assume they are not
|
||||
// traversed in such a manner. So instead, we will
|
||||
// simplify things for now by treating all generators as
|
||||
// if they were like trait objects, where its upvars must
|
||||
// all be alive for the generator's (potential)
|
||||
// destructor.
|
||||
//
|
||||
// In particular, skipping over `_interior` is safe
|
||||
// because any side-effects from dropping `_interior` can
|
||||
// only take place through references with lifetimes
|
||||
// derived from lifetimes attached to the upvars and resume
|
||||
// argument, and we *do* incorporate those here.
|
||||
|
||||
if !substs.as_generator().is_valid() {
|
||||
// By the time this code runs, all type variables ought to
|
||||
// be fully resolved.
|
||||
tcx.sess.delay_span_bug(
|
||||
span,
|
||||
format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
|
||||
);
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
constraints.outlives.extend(
|
||||
substs
|
||||
.as_generator()
|
||||
.upvar_tys()
|
||||
.map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }),
|
||||
);
|
||||
constraints.outlives.push(substs.as_generator().resume_ty().into());
|
||||
}
|
||||
|
||||
ty::Adt(def, substs) => {
|
||||
let DropckConstraint { dtorck_types, outlives, overflows } =
|
||||
tcx.at(span).adt_dtorck_constraint(def.did())?;
|
||||
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
|
||||
// there, but that needs some way to handle cycles.
|
||||
constraints
|
||||
.dtorck_types
|
||||
.extend(dtorck_types.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs)));
|
||||
constraints
|
||||
.outlives
|
||||
.extend(outlives.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs)));
|
||||
constraints
|
||||
.overflows
|
||||
.extend(overflows.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs)));
|
||||
}
|
||||
|
||||
// Objects must be alive in order for their destructor
|
||||
// to be called.
|
||||
ty::Dynamic(..) => {
|
||||
constraints.outlives.push(ty.into());
|
||||
}
|
||||
|
||||
// Types that can't be resolved. Pass them forward.
|
||||
ty::Alias(..) | ty::Param(..) => {
|
||||
constraints.dtorck_types.push(ty);
|
||||
}
|
||||
|
||||
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
|
||||
// By the time this code runs, all type variables ought to
|
||||
// be fully resolved.
|
||||
return Err(NoSolution);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserSelfTy, UserSubsts, UserType};
|
||||
|
||||
pub use rustc_middle::traits::query::type_op::AscribeUserType;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
||||
type QueryResponse = ();
|
||||
|
|
@ -20,4 +25,116 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
|||
) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
|
||||
tcx.type_op_ascribe_user_type(canonicalized)
|
||||
}
|
||||
|
||||
fn perform_locally_in_new_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
type_op_ascribe_user_type_with_span(ocx, key, None)
|
||||
}
|
||||
}
|
||||
|
||||
/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
|
||||
/// this query can be re-run to better track the span of the obligation cause, and improve the error
|
||||
/// message. Do not call directly unless you're in that very specific context.
|
||||
pub fn type_op_ascribe_user_type_with_span<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
|
||||
span: Option<Span>,
|
||||
) -> Result<(), NoSolution> {
|
||||
let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
|
||||
debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
|
||||
let span = span.unwrap_or(DUMMY_SP);
|
||||
match user_ty {
|
||||
UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
|
||||
UserType::TypeOf(def_id, user_substs) => {
|
||||
relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(ocx, param_env, span))]
|
||||
fn relate_mir_and_user_ty<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
mir_ty: Ty<'tcx>,
|
||||
user_ty: Ty<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
let cause = ObligationCause::dummy_with_span(span);
|
||||
let user_ty = ocx.normalize(&cause, param_env, user_ty);
|
||||
ocx.eq(&cause, param_env, mir_ty, user_ty)?;
|
||||
|
||||
// FIXME(#104764): We should check well-formedness before normalization.
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
|
||||
ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(ocx, param_env, span))]
|
||||
fn relate_mir_and_user_substs<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
mir_ty: Ty<'tcx>,
|
||||
def_id: DefId,
|
||||
user_substs: UserSubsts<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
let param_env = param_env.without_const();
|
||||
let UserSubsts { user_self_ty, substs } = user_substs;
|
||||
let tcx = ocx.infcx.tcx;
|
||||
let cause = ObligationCause::dummy_with_span(span);
|
||||
|
||||
let ty = tcx.type_of(def_id).subst(tcx, substs);
|
||||
let ty = ocx.normalize(&cause, param_env, ty);
|
||||
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
|
||||
|
||||
ocx.eq(&cause, param_env, mir_ty, ty)?;
|
||||
|
||||
// Prove the predicates coming along with `def_id`.
|
||||
//
|
||||
// Also, normalize the `instantiated_predicates`
|
||||
// because otherwise we wind up with duplicate "type
|
||||
// outlives" error messages.
|
||||
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
|
||||
|
||||
debug!(?instantiated_predicates);
|
||||
for (instantiated_predicate, predicate_span) in instantiated_predicates {
|
||||
let span = if span == DUMMY_SP { predicate_span } else { span };
|
||||
let cause = ObligationCause::new(
|
||||
span,
|
||||
CRATE_DEF_ID,
|
||||
ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
|
||||
);
|
||||
let instantiated_predicate =
|
||||
ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
|
||||
|
||||
ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
|
||||
}
|
||||
|
||||
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
||||
let self_ty = ocx.normalize(&cause, param_env, self_ty);
|
||||
let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs);
|
||||
let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
|
||||
|
||||
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
|
||||
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
|
||||
}
|
||||
|
||||
// In addition to proving the predicates, we have to
|
||||
// prove that `ty` is well-formed -- this is because
|
||||
// the WF of `ty` is predicated on the substs being
|
||||
// well-formed, and we haven't proven *that*. We don't
|
||||
// want to prove the WF of types from `substs` directly because they
|
||||
// haven't been normalized.
|
||||
//
|
||||
// FIXME(nmatsakis): Well, perhaps we should normalize
|
||||
// them? This would only be relevant if some input
|
||||
// type were ill-formed but did not appear in `ty`,
|
||||
// which...could happen with normalization...
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
|
||||
ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
|
||||
pub use rustc_middle::traits::query::type_op::Eq;
|
||||
|
|
@ -20,4 +22,12 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
|
|||
) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
|
||||
tcx.type_op_eq(canonicalized)
|
||||
}
|
||||
|
||||
fn perform_locally_in_new_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
ocx.eq(&ObligationCause::dummy(), key.param_env, key.value.a, key.value.b)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::wf;
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
|
||||
use rustc_infer::traits::query::OutlivesBound;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct ImpliedOutlivesBounds<'tcx> {
|
||||
|
|
@ -39,4 +47,169 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
|
|||
|
||||
tcx.implied_outlives_bounds(canonicalized)
|
||||
}
|
||||
|
||||
fn perform_locally_in_new_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_implied_outlives_bounds_inner<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
|
||||
// Sometimes when we ask what it takes for T: WF, we get back that
|
||||
// U: WF is required; in that case, we push U onto this stack and
|
||||
// process it next. Because the resulting predicates aren't always
|
||||
// guaranteed to be a subset of the original type, so we need to store the
|
||||
// WF args we've computed in a set.
|
||||
let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
|
||||
let mut wf_args = vec![ty.into()];
|
||||
|
||||
let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
|
||||
vec![];
|
||||
|
||||
while let Some(arg) = wf_args.pop() {
|
||||
if !checked_wf_args.insert(arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compute the obligations for `arg` to be well-formed. If `arg` is
|
||||
// an unresolved inference variable, just substituted an empty set
|
||||
// -- because the return type here is going to be things we *add*
|
||||
// to the environment, it's always ok for this set to be smaller
|
||||
// than the ultimate set. (Note: normally there won't be
|
||||
// unresolved inference variables here anyway, but there might be
|
||||
// during typeck under some circumstances.)
|
||||
//
|
||||
// FIXME(@lcnr): It's not really "always fine", having fewer implied
|
||||
// bounds can be backward incompatible, e.g. #101951 was caused by
|
||||
// us not dealing with inference vars in `TypeOutlives` predicates.
|
||||
let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
|
||||
.unwrap_or_default();
|
||||
|
||||
for obligation in obligations {
|
||||
debug!(?obligation);
|
||||
assert!(!obligation.has_escaping_bound_vars());
|
||||
|
||||
// While these predicates should all be implied by other parts of
|
||||
// the program, they are still relevant as they may constrain
|
||||
// inference variables, which is necessary to add the correct
|
||||
// implied bounds in some cases, mostly when dealing with projections.
|
||||
//
|
||||
// Another important point here: we only register `Projection`
|
||||
// predicates, since otherwise we might register outlives
|
||||
// predicates containing inference variables, and we don't
|
||||
// learn anything new from those.
|
||||
if obligation.predicate.has_non_region_infer() {
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::AliasRelate(..) => {
|
||||
ocx.register_obligation(obligation.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let pred = match obligation.predicate.kind().no_bound_vars() {
|
||||
None => continue,
|
||||
Some(pred) => pred,
|
||||
};
|
||||
match pred {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
// FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
|
||||
// if we ever support that
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
|
||||
|
||||
// We need to search through *all* WellFormed predicates
|
||||
ty::PredicateKind::WellFormed(arg) => {
|
||||
wf_args.push(arg);
|
||||
}
|
||||
|
||||
// We need to register region relationships
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
|
||||
r_a,
|
||||
r_b,
|
||||
))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
|
||||
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty_a,
|
||||
r_b,
|
||||
))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This call to `select_all_or_error` is necessary to constrain inference variables, which we
|
||||
// use further down when computing the implied bounds.
|
||||
match ocx.select_all_or_error().as_slice() {
|
||||
[] => (),
|
||||
_ => return Err(NoSolution),
|
||||
}
|
||||
|
||||
// We lazily compute the outlives components as
|
||||
// `select_all_or_error` constrains inference variables.
|
||||
let implied_bounds = outlives_bounds
|
||||
.into_iter()
|
||||
.flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
|
||||
ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
|
||||
ty::GenericArgKind::Type(ty_a) => {
|
||||
let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
|
||||
let mut components = smallvec![];
|
||||
push_outlives_components(tcx, ty_a, &mut components);
|
||||
implied_bounds_from_components(r_b, components)
|
||||
}
|
||||
ty::GenericArgKind::Const(_) => unreachable!(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(implied_bounds)
|
||||
}
|
||||
|
||||
/// When we have an implied bound that `T: 'a`, we can further break
|
||||
/// this down to determine what relationships would have to hold for
|
||||
/// `T: 'a` to hold. We get to assume that the caller has validated
|
||||
/// those relationships.
|
||||
fn implied_bounds_from_components<'tcx>(
|
||||
sub_region: ty::Region<'tcx>,
|
||||
sup_components: SmallVec<[Component<'tcx>; 4]>,
|
||||
) -> Vec<OutlivesBound<'tcx>> {
|
||||
sup_components
|
||||
.into_iter()
|
||||
.filter_map(|component| {
|
||||
match component {
|
||||
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
|
||||
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
|
||||
Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
|
||||
Component::EscapingAlias(_) =>
|
||||
// If the projection has escaping regions, don't
|
||||
// try to infer any implied bounds even for its
|
||||
// free components. This is conservative, because
|
||||
// the caller will still have to prove that those
|
||||
// free components outlive `sub_region`. But the
|
||||
// idea is that the WAY that the caller proves
|
||||
// that may change in the future and we want to
|
||||
// give ourselves room to get smarter here.
|
||||
{
|
||||
None
|
||||
}
|
||||
Component::UnresolvedInferenceVariable(..) => None,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::infer::canonical::{
|
|||
Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
|
||||
};
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::ObligationCause;
|
||||
use crate::traits::{ObligationCause, ObligationCtxt};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_infer::infer::canonical::Certainty;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
|
|
@ -23,6 +23,8 @@ pub mod subtype;
|
|||
|
||||
pub use rustc_middle::traits::query::type_op::*;
|
||||
|
||||
use self::custom::scrape_region_constraints;
|
||||
|
||||
/// "Type ops" are used in NLL to perform some particular action and
|
||||
/// extract out the resulting region constraints (or an error if it
|
||||
/// cannot be completed).
|
||||
|
|
@ -81,6 +83,17 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
|
|||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution>;
|
||||
|
||||
/// In the new trait solver, we already do caching in the solver itself,
|
||||
/// so there's no need to canonicalize and cache via the query system.
|
||||
/// Additionally, even if we were to canonicalize, we'd still need to
|
||||
/// make sure to feed it predefined opaque types and the defining anchor
|
||||
/// and that would require duplicating all of the tcx queries. Instead,
|
||||
/// just perform these ops locally.
|
||||
fn perform_locally_in_new_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
) -> Result<Self::QueryResponse, NoSolution>;
|
||||
|
||||
fn fully_perform_into(
|
||||
query_key: ParamEnvAnd<'tcx, Self>,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
|
|
@ -133,6 +146,16 @@ where
|
|||
infcx: &InferCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
|
||||
if infcx.tcx.trait_solver_next() {
|
||||
return Ok(scrape_region_constraints(
|
||||
infcx,
|
||||
|ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self),
|
||||
"query type op",
|
||||
span,
|
||||
)?
|
||||
.0);
|
||||
}
|
||||
|
||||
let mut region_constraints = QueryRegionConstraints::default();
|
||||
let (output, error_info, mut obligations, _) =
|
||||
Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
|
||||
|
|
|
|||
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