Merge from rustc

This commit is contained in:
Ben Kimock 2023-05-28 22:03:06 -04:00
commit fe69acfdf0
264 changed files with 5364 additions and 3471 deletions

View file

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

View file

@ -40,6 +40,7 @@ members = [
"src/tools/generate-copyright",
"src/tools/suggest-tests",
"src/tools/generate-windows-sys",
"src/tools/rustdoc-gui-test",
]
exclude = [

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -196,6 +196,7 @@ pub enum AttributeKind {
AllocSize = 37,
AllocatedPointer = 38,
AllocAlign = 39,
SanitizeSafeStack = 40,
}
/// LLVMIntPredicate

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -68,7 +68,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
}
}
ty::EarlyBinder(required_predicates)
ty::EarlyBinder::new(required_predicates)
})
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -96,6 +96,7 @@ enum LLVMRustAttribute {
AllocatedPointer = 38,
AllocAlign = 39,
#endif
SanitizeSafeStack = 40,
};
typedef struct OpaqueRustString *RustStringRef;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -504,6 +504,7 @@ macro_rules! make_mir_visitor {
place,
target: _,
unwind: _,
replace: _,
} => {
self.visit_place(
place,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -725,6 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: to_drop,
target: success,
unwind: UnwindAction::Continue,
replace: false,
},
);
this.diverge_from(block);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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];
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,6 +11,7 @@ pub fn target() -> Target {
| SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::SAFESTACK
| SanitizerSet::THREAD;
base.supports_xray = true;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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