Auto merge of #126332 - GuillaumeGomez:rollup-bu1q4pz, r=GuillaumeGomez

Rollup of 9 pull requests

Successful merges:

 - #126039 (Promote `arm64ec-pc-windows-msvc` to tier 2)
 - #126075 (Remove `DebugWithInfcx` machinery)
 - #126228 (Provide correct parent for nested anon const)
 - #126232 (interpret: dyn trait metadata check: equate traits in a proper way)
 - #126242 (Simplify provider api to improve llvm ir)
 - #126294 (coverage: Replace the old span refiner with a single function)
 - #126295 (No uninitalized report in a pre-returned match arm)
 - #126312 (Update `rustc-perf` submodule)
 - #126322 (Follow up to splitting core's PanicInfo and std's PanicInfo)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-06-12 15:58:32 +00:00
commit 1d43fbbc73
51 changed files with 561 additions and 851 deletions

View File

@ -557,8 +557,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// for the branching codepaths that aren't covered, to point at them. // for the branching codepaths that aren't covered, to point at them.
let map = self.infcx.tcx.hir(); let map = self.infcx.tcx.hir();
let body = map.body_owned_by(self.mir_def_id()); let body = map.body_owned_by(self.mir_def_id());
let mut visitor =
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] }; ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
visitor.visit_body(&body); visitor.visit_body(&body);
let mut show_assign_sugg = false; let mut show_assign_sugg = false;
@ -4372,13 +4372,14 @@ impl<'hir> Visitor<'hir> for BreakFinder {
/// Given a set of spans representing statements initializing the relevant binding, visit all the /// Given a set of spans representing statements initializing the relevant binding, visit all the
/// function expressions looking for branching code paths that *do not* initialize the binding. /// function expressions looking for branching code paths that *do not* initialize the binding.
struct ConditionVisitor<'b> { struct ConditionVisitor<'b, 'tcx> {
tcx: TyCtxt<'tcx>,
spans: &'b [Span], spans: &'b [Span],
name: &'b str, name: &'b str,
errors: Vec<(Span, String)>, errors: Vec<(Span, String)>,
} }
impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
match ex.kind { match ex.kind {
hir::ExprKind::If(cond, body, None) => { hir::ExprKind::If(cond, body, None) => {
@ -4464,6 +4465,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
), ),
)); ));
} else if let Some(guard) = &arm.guard { } else if let Some(guard) = &arm.guard {
if matches!(
self.tcx.hir_node(arm.body.hir_id),
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
) {
continue;
}
self.errors.push(( self.errors.push((
arm.pat.span.to(guard.span), arm.pat.span.to(guard.span),
format!( format!(
@ -4473,6 +4480,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
), ),
)); ));
} else { } else {
if matches!(
self.tcx.hir_node(arm.body.hir_id),
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
) {
continue;
}
self.errors.push(( self.errors.push((
arm.pat.span, arm.pat.span,
format!( format!(

View File

@ -387,7 +387,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
(&ty::Array(_, length), &ty::Slice(_)) => { (&ty::Array(_, length), &ty::Slice(_)) => {
let ptr = self.read_pointer(src)?; let ptr = self.read_pointer(src)?;
// u64 cast is from usize to u64, which is always good
let val = Immediate::new_slice( let val = Immediate::new_slice(
ptr, ptr,
length.eval_target_usize(*self.tcx, self.param_env), length.eval_target_usize(*self.tcx, self.param_env),
@ -405,13 +404,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (old_data, old_vptr) = val.to_scalar_pair(); let (old_data, old_vptr) = val.to_scalar_pair();
let old_data = old_data.to_pointer(self)?; let old_data = old_data.to_pointer(self)?;
let old_vptr = old_vptr.to_pointer(self)?; let old_vptr = old_vptr.to_pointer(self)?;
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; let ty = self.get_ptr_vtable_ty(old_vptr, Some(data_a))?;
if old_trait != data_a.principal() {
throw_ub!(InvalidVTableTrait {
expected_trait: data_a,
vtable_trait: old_trait,
});
}
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
} }

View File

@ -765,10 +765,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
} }
Ok(Some((full_size, full_align))) Ok(Some((full_size, full_align)))
} }
ty::Dynamic(_, _, ty::Dyn) => { ty::Dynamic(expected_trait, _, ty::Dyn) => {
let vtable = metadata.unwrap_meta().to_pointer(self)?; let vtable = metadata.unwrap_meta().to_pointer(self)?;
// Read size and align from vtable (already checks size). // Read size and align from vtable (already checks size).
Ok(Some(self.get_vtable_size_and_align(vtable)?)) Ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))
} }
ty::Slice(_) | ty::Str => { ty::Slice(_) | ty::Str => {

View File

@ -432,12 +432,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
sym::vtable_size => { sym::vtable_size => {
let ptr = self.read_pointer(&args[0])?; let ptr = self.read_pointer(&args[0])?;
let (size, _align) = self.get_vtable_size_and_align(ptr)?; // `None` because we don't know which trait to expect here; any vtable is okay.
let (size, _align) = self.get_vtable_size_and_align(ptr, None)?;
self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?; self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?;
} }
sym::vtable_align => { sym::vtable_align => {
let ptr = self.read_pointer(&args[0])?; let ptr = self.read_pointer(&args[0])?;
let (_size, align) = self.get_vtable_size_and_align(ptr)?; // `None` because we don't know which trait to expect here; any vtable is okay.
let (_size, align) = self.get_vtable_size_and_align(ptr, None)?;
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
} }

View File

@ -867,19 +867,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
.ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
} }
pub fn get_ptr_vtable( /// Get the dynamic type of the given vtable pointer.
/// If `expected_trait` is `Some`, it must be a vtable for the given trait.
pub fn get_ptr_vtable_ty(
&self, &self,
ptr: Pointer<Option<M::Provenance>>, ptr: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)> { expected_trait: Option<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>,
) -> InterpResult<'tcx, Ty<'tcx>> {
trace!("get_ptr_vtable({:?})", ptr); trace!("get_ptr_vtable({:?})", ptr);
let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 { if offset.bytes() != 0 {
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))) throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
} }
match self.tcx.try_get_global_alloc(alloc_id) { let Some(GlobalAlloc::VTable(ty, vtable_trait)) = self.tcx.try_get_global_alloc(alloc_id)
Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)), else {
_ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))), throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
};
if let Some(expected_trait) = expected_trait {
self.check_vtable_for_type(vtable_trait, expected_trait)?;
} }
Ok(ty)
} }
pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {

View File

@ -9,7 +9,6 @@ use tracing::{instrument, trace};
use rustc_ast::Mutability; use rustc_ast::Mutability;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
@ -1018,54 +1017,6 @@ where
let layout = self.layout_of(raw.ty)?; let layout = self.layout_of(raw.ty)?;
Ok(self.ptr_to_mplace(ptr.into(), layout)) Ok(self.ptr_to_mplace(ptr.into(), layout))
} }
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
/// Aso returns the vtable.
pub(super) fn unpack_dyn_trait(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)> {
assert!(
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
"`unpack_dyn_trait` only makes sense on `dyn*` types"
);
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
if expected_trait.principal() != vtable_trait {
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
}
// This is a kind of transmute, from a place with unsized type and metadata to
// a place with sized type and no metadata.
let layout = self.layout_of(ty)?;
let mplace =
MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout };
Ok((mplace, vtable))
}
/// Turn a `dyn* Trait` type into an value with the actual dynamic type.
/// Also returns the vtable.
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
&self,
val: &P,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {
assert!(
matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
"`unpack_dyn_star` only makes sense on `dyn*` types"
);
let data = self.project_field(val, 0)?;
let vtable = self.project_field(val, 1)?;
let vtable = self.read_pointer(&vtable.to_op(self)?)?;
let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
if expected_trait.principal() != vtable_trait {
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
}
// `data` is already the right thing but has the wrong type. So we transmute it.
let layout = self.layout_of(ty)?;
let data = data.transmute(layout, self)?;
Ok((data, vtable))
}
} }
// Some nodes are used a lot. Make sure they don't unintentionally get bigger. // Some nodes are used a lot. Make sure they don't unintentionally get bigger.

View File

@ -1,6 +1,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use either::Either; use either::Either;
use rustc_middle::ty::TyCtxt;
use tracing::trace; use tracing::trace;
use rustc_middle::span_bug; use rustc_middle::span_bug;
@ -827,20 +828,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}; };
// Obtain the underlying trait we are working on, and the adjusted receiver argument. // Obtain the underlying trait we are working on, and the adjusted receiver argument.
let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) = let (dyn_trait, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) =
receiver_place.layout.ty.kind() receiver_place.layout.ty.kind()
{ {
let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?; let recv = self.unpack_dyn_star(&receiver_place, data)?;
let (dyn_ty, _dyn_trait) = self.get_ptr_vtable(vptr)?;
(vptr, dyn_ty, recv.ptr()) (data.principal(), recv.layout.ty, recv.ptr())
} else { } else {
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
// (For that reason we also cannot use `unpack_dyn_trait`.) // (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail = self let receiver_tail = self
.tcx .tcx
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
let ty::Dynamic(data, _, ty::Dyn) = receiver_tail.kind() else { let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
span_bug!( span_bug!(
self.cur_span(), self.cur_span(),
"dynamic call on non-`dyn` type {}", "dynamic call on non-`dyn` type {}",
@ -851,25 +851,24 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Get the required information from the vtable. // Get the required information from the vtable.
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
if dyn_trait != data.principal() {
throw_ub!(InvalidVTableTrait {
expected_trait: data,
vtable_trait: dyn_trait,
});
}
// It might be surprising that we use a pointer as the receiver even if this // It might be surprising that we use a pointer as the receiver even if this
// is a by-val case; this works because by-val passing of an unsized `dyn // is a by-val case; this works because by-val passing of an unsized `dyn
// Trait` to a function is actually desugared to a pointer. // Trait` to a function is actually desugared to a pointer.
(vptr, dyn_ty, receiver_place.ptr()) (receiver_trait.principal(), dyn_ty, receiver_place.ptr())
}; };
// Now determine the actual method to call. We can do that in two different ways and // Now determine the actual method to call. We can do that in two different ways and
// compare them to ensure everything fits. // compare them to ensure everything fits.
let Some(ty::VtblEntry::Method(fn_inst)) = let vtable_entries = if let Some(dyn_trait) = dyn_trait {
self.get_vtable_entries(vptr)?.get(idx).copied() let trait_ref = dyn_trait.with_self_ty(*self.tcx, dyn_ty);
else { let trait_ref = self.tcx.erase_regions(trait_ref);
self.tcx.vtable_entries(trait_ref)
} else {
TyCtxt::COMMON_VTABLE_ENTRIES
};
let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else {
// FIXME(fee1-dead) these could be variants of the UB info enum instead of this // FIXME(fee1-dead) these could be variants of the UB info enum instead of this
throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method); throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method);
}; };
@ -898,7 +897,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty); let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
args[0] = FnArg::Copy( args[0] = FnArg::Copy(
ImmTy::from_immediate( ImmTy::from_immediate(
Scalar::from_maybe_pointer(adjusted_receiver, self).into(), Scalar::from_maybe_pointer(adjusted_recv, self).into(),
self.layout_of(receiver_ty)?, self.layout_of(receiver_ty)?,
) )
.into(), .into(),
@ -974,11 +973,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let place = match place.layout.ty.kind() { let place = match place.layout.ty.kind() {
ty::Dynamic(data, _, ty::Dyn) => { ty::Dynamic(data, _, ty::Dyn) => {
// Dropping a trait object. Need to find actual drop fn. // Dropping a trait object. Need to find actual drop fn.
self.unpack_dyn_trait(&place, data)?.0 self.unpack_dyn_trait(&place, data)?
} }
ty::Dynamic(data, _, ty::DynStar) => { ty::Dynamic(data, _, ty::DynStar) => {
// Dropping a `dyn*`. Need to find actual drop fn. // Dropping a `dyn*`. Need to find actual drop fn.
self.unpack_dyn_star(&place, data)?.0 self.unpack_dyn_star(&place, data)?
} }
_ => { _ => {
debug_assert_eq!( debug_assert_eq!(

View File

@ -1,11 +1,14 @@
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::interpret::{InterpResult, Pointer}; use rustc_middle::mir::interpret::{InterpResult, Pointer};
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Align, Size}; use rustc_target::abi::{Align, Size};
use rustc_trait_selection::traits::ObligationCtxt;
use tracing::trace; use tracing::trace;
use super::util::ensure_monomorphic_enough; use super::util::ensure_monomorphic_enough;
use super::{InterpCx, Machine}; use super::{throw_ub, InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable};
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
@ -33,28 +36,90 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Ok(vtable_ptr.into()) Ok(vtable_ptr.into())
} }
/// Returns a high-level representation of the entries of the given vtable.
pub fn get_vtable_entries(
&self,
vtable: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> {
let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?;
Ok(if let Some(poly_trait_ref) = poly_trait_ref {
let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
let trait_ref = self.tcx.erase_regions(trait_ref);
self.tcx.vtable_entries(trait_ref)
} else {
TyCtxt::COMMON_VTABLE_ENTRIES
})
}
pub fn get_vtable_size_and_align( pub fn get_vtable_size_and_align(
&self, &self,
vtable: Pointer<Option<M::Provenance>>, vtable: Pointer<Option<M::Provenance>>,
expected_trait: Option<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>,
) -> InterpResult<'tcx, (Size, Align)> { ) -> InterpResult<'tcx, (Size, Align)> {
let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?; let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?;
let layout = self.layout_of(ty)?; let layout = self.layout_of(ty)?;
assert!(layout.is_sized(), "there are no vtables for unsized types"); assert!(layout.is_sized(), "there are no vtables for unsized types");
Ok((layout.size, layout.align.abi)) Ok((layout.size, layout.align.abi))
} }
/// Check that the given vtable trait is valid for a pointer/reference/place with the given
/// expected trait type.
pub(super) fn check_vtable_for_type(
&self,
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx> {
// Fast path: if they are equal, it's all fine.
if expected_trait.principal() == vtable_trait {
return Ok(());
}
if let (Some(expected_trait), Some(vtable_trait)) =
(expected_trait.principal(), vtable_trait)
{
// Slow path: spin up an inference context to check if these traits are sufficiently equal.
let infcx = self.tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy_with_span(self.cur_span());
// equate the two trait refs after normalization
let expected_trait = ocx.normalize(&cause, self.param_env, expected_trait);
let vtable_trait = ocx.normalize(&cause, self.param_env, vtable_trait);
if ocx.eq(&cause, self.param_env, expected_trait, vtable_trait).is_ok() {
if ocx.select_all_or_error().is_empty() {
// All good.
return Ok(());
}
}
}
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
}
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
pub(super) fn unpack_dyn_trait(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
assert!(
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
"`unpack_dyn_trait` only makes sense on `dyn*` types"
);
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
// This is a kind of transmute, from a place with unsized type and metadata to
// a place with sized type and no metadata.
let layout = self.layout_of(ty)?;
let mplace = mplace.offset_with_meta(
Size::ZERO,
OffsetMode::Wrapping,
MemPlaceMeta::None,
layout,
self,
)?;
Ok(mplace)
}
/// Turn a `dyn* Trait` type into an value with the actual dynamic type.
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
&self,
val: &P,
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, P> {
assert!(
matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
"`unpack_dyn_star` only makes sense on `dyn*` types"
);
let data = self.project_field(val, 0)?;
let vtable = self.project_field(val, 1)?;
let vtable = self.read_pointer(&vtable.to_op(self)?)?;
let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
// `data` is already the right thing but has the wrong type. So we transmute it.
let layout = self.layout_of(ty)?;
let data = data.transmute(layout, self)?;
Ok(data)
}
} }

View File

@ -343,20 +343,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
match tail.kind() { match tail.kind() {
ty::Dynamic(data, _, ty::Dyn) => { ty::Dynamic(data, _, ty::Dyn) => {
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
// Make sure it is a genuine vtable pointer. // Make sure it is a genuine vtable pointer for the right trait.
let (_dyn_ty, dyn_trait) = try_validation!( try_validation!(
self.ecx.get_ptr_vtable(vtable), self.ecx.get_ptr_vtable_ty(vtable, Some(data)),
self.path, self.path,
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) => Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
InvalidVTablePtr { value: format!("{vtable}") } InvalidVTablePtr { value: format!("{vtable}") },
Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
},
); );
// Make sure it is for the right trait.
if dyn_trait != data.principal() {
throw_validation_failure!(
self.path,
InvalidMetaWrongTrait { expected_trait: data, vtable_trait: dyn_trait }
);
}
} }
ty::Slice(..) | ty::Str => { ty::Slice(..) | ty::Str => {
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?; let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;

View File

@ -95,7 +95,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
// unsized values are never immediate, so we can assert_mem_place // unsized values are never immediate, so we can assert_mem_place
let op = v.to_op(self.ecx())?; let op = v.to_op(self.ecx())?;
let dest = op.assert_mem_place(); let dest = op.assert_mem_place();
let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?.0; let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?;
trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
// recurse with the inner type // recurse with the inner type
return self.visit_field(v, 0, &inner_mplace.into()); return self.visit_field(v, 0, &inner_mplace.into());
@ -104,7 +104,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
// DynStar types. Very different from a dyn type (but strangely part of the // DynStar types. Very different from a dyn type (but strangely part of the
// same variant in `TyKind`): These are pairs where the 2nd component is the // same variant in `TyKind`): These are pairs where the 2nd component is the
// vtable, and the first component is the data (which must be ptr-sized). // vtable, and the first component is the data (which must be ptr-sized).
let data = self.ecx().unpack_dyn_star(v, data)?.0; let data = self.ecx().unpack_dyn_star(v, data)?;
return self.visit_field(v, 0, &data); return self.visit_field(v, 0, &data);
} }
// Slices do not need special handling here: they have `Array` field // Slices do not need special handling here: they have `Array` field

View File

@ -11,6 +11,7 @@ use rustc_session::lint;
use rustc_span::symbol::{kw, Symbol}; use rustc_span::symbol::{kw, Symbol};
use rustc_span::Span; use rustc_span::Span;
#[instrument(level = "debug", skip(tcx))]
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
use rustc_hir::*; use rustc_hir::*;
@ -66,7 +67,22 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// FIXME(#43408) always enable this once `lazy_normalization` is // FIXME(#43408) always enable this once `lazy_normalization` is
// stable enough and does not need a feature gate anymore. // stable enough and does not need a feature gate anymore.
Node::AnonConst(_) => { Node::AnonConst(_) => {
let parent_def_id = tcx.hir().get_parent_item(hir_id); let parent_did = tcx.parent(def_id.to_def_id());
// We don't do this unconditionally because the `DefId` parent of an anon const
// might be an implicitly created closure during `async fn` desugaring. This would
// have the wrong generics.
//
// i.e. `async fn foo<'a>() { let a = [(); { 1 + 2 }]; bar().await() }`
// would implicitly have a closure in its body that would be the parent of
// the `{ 1 + 2 }` anon const. This closure's generics is simply a witness
// instead of `['a]`.
let parent_did = if let DefKind::AnonConst = tcx.def_kind(parent_did) {
parent_did
} else {
tcx.hir().get_parent_item(hir_id).to_def_id()
};
debug!(?parent_did);
let mut in_param_ty = false; let mut in_param_ty = false;
for (_parent, node) in tcx.hir().parent_iter(hir_id) { for (_parent, node) in tcx.hir().parent_iter(hir_id) {
@ -121,7 +137,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// //
// This has some implications for how we get the predicates available to the anon const // This has some implications for how we get the predicates available to the anon const
// see `explicit_predicates_of` for more information on this // see `explicit_predicates_of` for more information on this
let generics = tcx.generics_of(parent_def_id.to_def_id()); let generics = tcx.generics_of(parent_did);
let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()]; let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
// In the above example this would be .params[..N#0] // In the above example this would be .params[..N#0]
let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned(); let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned();
@ -147,7 +163,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// //
// Note that we do not supply the parent generics when using // Note that we do not supply the parent generics when using
// `min_const_generics`. // `min_const_generics`.
Some(parent_def_id.to_def_id()) Some(parent_did)
} }
} else { } else {
let parent_node = tcx.parent_hir_node(hir_id); let parent_node = tcx.parent_hir_node(hir_id);
@ -159,7 +175,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
if constant.hir_id() == hir_id => if constant.hir_id() == hir_id =>
{ {
Some(parent_def_id.to_def_id()) Some(parent_did)
} }
// Exclude `GlobalAsm` here which cannot have generics. // Exclude `GlobalAsm` here which cannot have generics.
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
@ -171,7 +187,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
_ => false, _ => false,
}) => }) =>
{ {
Some(parent_def_id.to_def_id()) Some(parent_did)
} }
_ => None, _ => None,
} }

View File

@ -1,5 +1,5 @@
use super::flags::FlagComputation; use super::flags::FlagComputation;
use super::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, TyCtxt, TypeFlags, WithInfcx}; use super::{DebruijnIndex, TypeFlags};
use crate::arena::Arena; use crate::arena::Arena;
use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_data_structures::aligned::{align_of, Aligned};
use rustc_serialize::{Encodable, Encoder}; use rustc_serialize::{Encodable, Encoder};
@ -162,14 +162,6 @@ impl<H, T: fmt::Debug> fmt::Debug for RawList<H, T> {
(**self).fmt(f) (**self).fmt(f)
} }
} }
impl<'tcx, H, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for RawList<H, T> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
fmt::Debug::fmt(&this.map(|this| this.as_slice()), f)
}
}
impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> { impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> {
#[inline] #[inline]

View File

@ -61,7 +61,6 @@ use rustc_span::{ExpnId, ExpnKind, Span};
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
pub use rustc_target::abi::{ReprFlags, ReprOptions}; pub use rustc_target::abi::{ReprFlags, ReprOptions};
pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::relate::VarianceDiagInfo;
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
pub use vtable::*; pub use vtable::*;

View File

@ -13,7 +13,7 @@ use rustc_ast_ir::visit::VisitorResult;
use rustc_hir::def::Namespace; use rustc_hir::def::Namespace;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_target::abi::TyAndLayout; use rustc_target::abi::TyAndLayout;
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx}; use rustc_type_ir::ConstKind;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
@ -83,14 +83,6 @@ impl fmt::Debug for ty::LateParamRegion {
} }
} }
impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
this.data.fmt(f)
}
}
impl<'tcx> fmt::Debug for Ty<'tcx> { impl<'tcx> fmt::Debug for Ty<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f)) with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f))
@ -121,70 +113,33 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match &**this.data {
ty::PatternKind::Range { start, end, include_end } => f
.debug_struct("Pattern::Range")
.field("start", start)
.field("end", end)
.field("include_end", include_end)
.finish(),
}
}
}
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f) match self.kind {
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match this.data.kind {
ty::ExprKind::Binop(op) => { ty::ExprKind::Binop(op) => {
let (lhs_ty, rhs_ty, lhs, rhs) = this.data.binop_args(); let (lhs_ty, rhs_ty, lhs, rhs) = self.binop_args();
write!( write!(f, "({op:?}: ({:?}: {:?}), ({:?}: {:?}))", lhs, lhs_ty, rhs, rhs_ty,)
f,
"({op:?}: ({:?}: {:?}), ({:?}: {:?}))",
&this.wrap(lhs),
&this.wrap(lhs_ty),
&this.wrap(rhs),
&this.wrap(rhs_ty),
)
} }
ty::ExprKind::UnOp(op) => { ty::ExprKind::UnOp(op) => {
let (rhs_ty, rhs) = this.data.unop_args(); let (rhs_ty, rhs) = self.unop_args();
write!(f, "({op:?}: ({:?}: {:?}))", &this.wrap(rhs), &this.wrap(rhs_ty)) write!(f, "({op:?}: ({:?}: {:?}))", rhs, rhs_ty)
} }
ty::ExprKind::FunctionCall => { ty::ExprKind::FunctionCall => {
let (func_ty, func, args) = this.data.call_args(); let (func_ty, func, args) = self.call_args();
let args = args.collect::<Vec<_>>(); let args = args.collect::<Vec<_>>();
write!(f, "({:?}: {:?})(", &this.wrap(func), &this.wrap(func_ty))?; write!(f, "({:?}: {:?})(", func, func_ty)?;
for arg in args.iter().rev().skip(1).rev() { for arg in args.iter().rev().skip(1).rev() {
write!(f, "{:?}, ", &this.wrap(arg))?; write!(f, "{:?}, ", arg)?;
} }
if let Some(arg) = args.last() { if let Some(arg) = args.last() {
write!(f, "{:?}", &this.wrap(arg))?; write!(f, "{:?}", arg)?;
} }
write!(f, ")") write!(f, ")")
} }
ty::ExprKind::Cast(kind) => { ty::ExprKind::Cast(kind) => {
let (value_ty, value, to_ty) = this.data.cast_args(); let (value_ty, value, to_ty) = self.cast_args();
write!( write!(f, "({kind:?}: ({:?}: {:?}), {:?})", value, value_ty, to_ty)
f,
"({kind:?}: ({:?}: {:?}), {:?})",
&this.wrap(value),
&this.wrap(value_ty),
&this.wrap(to_ty)
)
} }
} }
} }
@ -192,20 +147,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
impl<'tcx> fmt::Debug for ty::Const<'tcx> { impl<'tcx> fmt::Debug for ty::Const<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
// If this is a value, we spend some effort to make it look nice. // If this is a value, we spend some effort to make it look nice.
if let ConstKind::Value(_, _) = this.data.kind() { if let ConstKind::Value(_, _) = self.kind() {
return ty::tls::with(move |tcx| { return ty::tls::with(move |tcx| {
// Somehow trying to lift the valtree results in lifetime errors, so we lift the // Somehow trying to lift the valtree results in lifetime errors, so we lift the
// entire constant. // entire constant.
let lifted = tcx.lift(*this.data).unwrap(); let lifted = tcx.lift(*self).unwrap();
let ConstKind::Value(ty, valtree) = lifted.kind() else { let ConstKind::Value(ty, valtree) = lifted.kind() else {
bug!("we checked that this is a valtree") bug!("we checked that this is a valtree")
}; };
@ -215,7 +162,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
}); });
} }
// Fall back to something verbose. // Fall back to something verbose.
write!(f, "{kind:?}", kind = &this.map(|data| data.kind())) write!(f, "{:?}", self.kind())
} }
} }
@ -247,32 +194,12 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> {
} }
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match this.data.unpack() {
GenericArgKind::Lifetime(lt) => write!(f, "{:?}", &this.wrap(lt)),
GenericArgKind::Const(ct) => write!(f, "{:?}", &this.wrap(ct)),
GenericArgKind::Type(ty) => write!(f, "{:?}", &this.wrap(ty)),
}
}
}
impl<'tcx> fmt::Debug for Region<'tcx> { impl<'tcx> fmt::Debug for Region<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.kind()) write!(f, "{:?}", self.kind())
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
write!(f, "{:?}", &this.map(|data| data.kind()))
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Atomic structs // Atomic structs

View File

@ -1,6 +1,5 @@
use rustc_middle::bug;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_span::{BytePos, Span}; use rustc_span::Span;
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
use crate::coverage::mappings; use crate::coverage::mappings;
@ -23,7 +22,7 @@ pub(super) fn extract_refined_covspans(
let sorted_span_buckets = let sorted_span_buckets =
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
for bucket in sorted_span_buckets { for bucket in sorted_span_buckets {
let refined_spans = SpansRefiner::refine_sorted_spans(bucket); let refined_spans = refine_sorted_spans(bucket);
code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| { code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| {
// Each span produced by the refiner represents an ordinary code region. // Each span produced by the refiner represents an ordinary code region.
mappings::CodeMapping { span, bcb } mappings::CodeMapping { span, bcb }
@ -31,58 +30,6 @@ pub(super) fn extract_refined_covspans(
} }
} }
#[derive(Debug)]
struct CurrCovspan {
span: Span,
bcb: BasicCoverageBlock,
}
impl CurrCovspan {
fn new(span: Span, bcb: BasicCoverageBlock) -> Self {
Self { span, bcb }
}
fn into_prev(self) -> PrevCovspan {
let Self { span, bcb } = self;
PrevCovspan { span, bcb, merged_spans: vec![span] }
}
}
#[derive(Debug)]
struct PrevCovspan {
span: Span,
bcb: BasicCoverageBlock,
/// List of all the original spans from MIR that have been merged into this
/// span. Mainly used to precisely skip over gaps when truncating a span.
merged_spans: Vec<Span>,
}
impl PrevCovspan {
fn is_mergeable(&self, other: &CurrCovspan) -> bool {
self.bcb == other.bcb
}
fn merge_from(&mut self, other: &CurrCovspan) {
debug_assert!(self.is_mergeable(other));
self.span = self.span.to(other.span);
self.merged_spans.push(other.span);
}
fn cutoff_statements_at(mut self, cutoff_pos: BytePos) -> Option<RefinedCovspan> {
self.merged_spans.retain(|span| span.hi() <= cutoff_pos);
if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() {
self.span = self.span.with_hi(max_hi);
}
if self.merged_spans.is_empty() { None } else { Some(self.into_refined()) }
}
fn into_refined(self) -> RefinedCovspan {
let Self { span, bcb, merged_spans: _ } = self;
RefinedCovspan { span, bcb }
}
}
#[derive(Debug)] #[derive(Debug)]
struct RefinedCovspan { struct RefinedCovspan {
span: Span, span: Span,
@ -100,164 +47,50 @@ impl RefinedCovspan {
} }
} }
/// Converts the initial set of coverage spans (one per MIR `Statement` or `Terminator`) into a /// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines"
/// minimal set of coverage spans, using the BCB CFG to determine where it is safe and useful to: /// those spans by removing spans that overlap in unwanted ways, and by merging
/// /// compatible adjacent spans.
/// * Remove duplicate source code coverage regions #[instrument(level = "debug")]
/// * Merge spans that represent continuous (both in source code and control flow), non-branching fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
/// execution // Holds spans that have been read from the input vector, but haven't yet
struct SpansRefiner { // been committed to the output vector.
/// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative let mut pending = vec![];
/// dominance between the `BasicCoverageBlock`s of equal `Span`s. let mut refined = vec![];
sorted_spans_iter: std::vec::IntoIter<SpanFromMir>,
/// The current coverage span to compare to its `prev`, to possibly merge, discard, for curr in sorted_spans {
/// or cause `prev` to be modified or discarded. pending.retain(|prev: &SpanFromMir| {
/// If `curr` is not discarded or merged, it becomes `prev` for the next iteration. if prev.span.hi() <= curr.span.lo() {
some_curr: Option<CurrCovspan>, // There's no overlap between the previous/current covspans,
// so move the previous one into the refined list.
/// The coverage span from a prior iteration; typically assigned from that iteration's `curr`. refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
/// If that `curr` was discarded, `prev` retains its value from the previous iteration.
some_prev: Option<PrevCovspan>,
/// The final coverage spans to add to the coverage map. A `Counter` or `Expression`
/// will also be injected into the MIR for each BCB that has associated spans.
refined_spans: Vec<RefinedCovspan>,
}
impl SpansRefiner {
/// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
/// them by merging compatible adjacent spans, removing redundant spans,
/// and carving holes in spans when they overlap in unwanted ways.
fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
let sorted_spans_len = sorted_spans.len();
let this = Self {
sorted_spans_iter: sorted_spans.into_iter(),
some_curr: None,
some_prev: None,
refined_spans: Vec::with_capacity(sorted_spans_len),
};
this.to_refined_spans()
}
/// Iterate through the sorted coverage spans, and return the refined list of merged and
/// de-duplicated spans.
fn to_refined_spans(mut self) -> Vec<RefinedCovspan> {
while self.next_coverage_span() {
// For the first span we don't have `prev` set, so most of the
// span-processing steps don't make sense yet.
if self.some_prev.is_none() {
debug!(" initial span");
continue;
}
// The remaining cases assume that `prev` and `curr` are set.
let prev = self.prev();
let curr = self.curr();
if prev.is_mergeable(curr) {
debug!(?prev, "curr will be merged into prev");
let curr = self.take_curr();
self.prev_mut().merge_from(&curr);
} else if prev.span.hi() <= curr.span.lo() {
debug!(
" different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}",
);
let prev = self.take_prev().into_refined();
self.refined_spans.push(prev);
} else {
self.cutoff_prev_at_overlapping_curr();
}
}
// There is usually a final span remaining in `prev` after the loop ends,
// so add it to the output as well.
if let Some(prev) = self.some_prev.take() {
debug!(" AT END, adding last prev={prev:?}");
self.refined_spans.push(prev.into_refined());
}
// Do one last merge pass, to simplify the output.
self.refined_spans.dedup_by(|b, a| {
if a.is_mergeable(b) {
debug!(?a, ?b, "merging list-adjacent refined spans");
a.merge_from(b);
true
} else {
false false
} else {
// Otherwise, retain the previous covspan only if it has the
// same BCB. This tends to discard long outer spans that enclose
// smaller inner spans with different control flow.
prev.bcb == curr.bcb
} }
}); });
pending.push(curr);
self.refined_spans
} }
#[track_caller] // Drain the rest of the pending list into the refined list.
fn curr(&self) -> &CurrCovspan { for prev in pending {
self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)")) refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
} }
/// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the // Do one last merge pass, to simplify the output.
/// `curr` coverage span. debug!(?refined, "before merge");
#[track_caller] refined.dedup_by(|b, a| {
fn take_curr(&mut self) -> CurrCovspan { if a.is_mergeable(b) {
self.some_curr.take().unwrap_or_else(|| bug!("some_curr is None (take_curr)")) debug!(?a, ?b, "merging list-adjacent refined spans");
} a.merge_from(b);
#[track_caller]
fn prev(&self) -> &PrevCovspan {
self.some_prev.as_ref().unwrap_or_else(|| bug!("some_prev is None (prev)"))
}
#[track_caller]
fn prev_mut(&mut self) -> &mut PrevCovspan {
self.some_prev.as_mut().unwrap_or_else(|| bug!("some_prev is None (prev_mut)"))
}
#[track_caller]
fn take_prev(&mut self) -> PrevCovspan {
self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)"))
}
/// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order.
fn next_coverage_span(&mut self) -> bool {
if let Some(curr) = self.some_curr.take() {
self.some_prev = Some(curr.into_prev());
}
if let Some(SpanFromMir { span, bcb, .. }) = self.sorted_spans_iter.next() {
// This code only sees sorted spans after hole-carving, so there should
// be no way for `curr` to start before `prev`.
if let Some(prev) = &self.some_prev {
debug_assert!(prev.span.lo() <= span.lo());
}
self.some_curr = Some(CurrCovspan::new(span, bcb));
debug!(?self.some_prev, ?self.some_curr, "next_coverage_span");
true true
} else { } else {
false false
} }
} });
debug!(?refined, "after merge");
/// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_ refined
/// statements that end before `curr.lo()` (if any), and add the portion of the
/// combined span for those statements. Any other statements have overlapping spans
/// that can be ignored because `curr` and/or other upcoming statements/spans inside
/// the overlap area will produce their own counters. This disambiguation process
/// avoids injecting multiple counters for overlapping spans, and the potential for
/// double-counting.
fn cutoff_prev_at_overlapping_curr(&mut self) {
debug!(
" different bcbs, overlapping spans, so ignore/drop pending and only add prev \
if it has statements that end before curr; prev={:?}",
self.prev()
);
let curr_span = self.curr().span;
if let Some(prev) = self.take_prev().cutoff_statements_at(curr_span.lo()) {
debug!("after cutoff, adding {prev:?}");
self.refined_spans.push(prev);
} else {
debug!("prev was eliminated by cutoff");
}
}
} }

View File

@ -8,12 +8,11 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_serialize::Decodable; use rustc_serialize::Decodable;
use tracing::debug; use tracing::debug;
use crate::debug::{DebugWithInfcx, WithInfcx};
use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
use crate::inherent::*; use crate::inherent::*;
use crate::lift::Lift; use crate::lift::Lift;
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use crate::{self as ty, InferCtxtLike, Interner, SsoHashSet}; use crate::{self as ty, Interner, SsoHashSet};
/// Binder is a binder for higher-ranked lifetimes or types. It is part of the /// Binder is a binder for higher-ranked lifetimes or types. It is part of the
/// compiler's representation for things like `for<'a> Fn(&'a isize)` /// compiler's representation for things like `for<'a> Fn(&'a isize)`
@ -56,18 +55,6 @@ where
} }
} }
impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for ty::Binder<I, T> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
f.debug_tuple("Binder")
.field(&this.map(|data| data.as_ref().skip_binder()))
.field(&this.data.bound_vars())
.finish()
}
}
macro_rules! impl_binder_encode_decode { macro_rules! impl_binder_encode_decode {
($($t:ty),+ $(,)?) => { ($($t:ty),+ $(,)?) => {
$( $(

View File

@ -5,7 +5,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use std::fmt; use std::fmt;
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use crate::{self as ty, DebruijnIndex, Interner};
use self::ConstKind::*; use self::ConstKind::*;
@ -61,28 +61,19 @@ impl<I: Interner> PartialEq for ConstKind<I> {
impl<I: Interner> fmt::Debug for ConstKind<I> { impl<I: Interner> fmt::Debug for ConstKind<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
use ConstKind::*; use ConstKind::*;
match this.data { match self {
Param(param) => write!(f, "{param:?}"), Param(param) => write!(f, "{param:?}"),
Infer(var) => write!(f, "{:?}", &this.wrap(var)), Infer(var) => write!(f, "{:?}", &var),
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var), Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
Placeholder(placeholder) => write!(f, "{placeholder:?}"), Placeholder(placeholder) => write!(f, "{placeholder:?}"),
Unevaluated(uv) => { Unevaluated(uv) => {
write!(f, "{:?}", &this.wrap(uv)) write!(f, "{:?}", &uv)
} }
Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &this.wrap(ty)), Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &ty),
Error(_) => write!(f, "{{const error}}"), Error(_) => write!(f, "{{const error}}"),
Expr(expr) => write!(f, "{:?}", &this.wrap(expr)), Expr(expr) => write!(f, "{:?}", &expr),
} }
} }
} }
@ -112,17 +103,9 @@ impl<I: Interner> UnevaluatedConst<I> {
impl<I: Interner> fmt::Debug for UnevaluatedConst<I> { impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
f.debug_struct("UnevaluatedConst") f.debug_struct("UnevaluatedConst")
.field("def", &this.data.def) .field("def", &self.def)
.field("args", &this.wrap(this.data.args)) .field("args", &self.args)
.finish() .finish()
} }
} }
@ -175,23 +158,6 @@ impl fmt::Debug for InferConst {
} }
} }
} }
impl<I: Interner> DebugWithInfcx<I> for InferConst {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match *this.data {
InferConst::Var(vid) => match this.infcx.universe_of_ct(vid) {
None => write!(f, "{:?}", this.data),
Some(universe) => write!(f, "?{}_{}c", vid.index(), universe.index()),
},
InferConst::EffectVar(vid) => write!(f, "?{}e", vid.index()),
InferConst::Fresh(_) => {
unreachable!()
}
}
}
}
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
impl<CTX> HashStable<CTX> for InferConst { impl<CTX> HashStable<CTX> for InferConst {

View File

@ -1,146 +0,0 @@
use crate::{
ConstVid, EffectVid, FloatVid, InferCtxtLike, IntVid, Interner, RegionVid, TyVid, UniverseIndex,
};
use core::fmt;
use std::marker::PhantomData;
pub struct NoInfcx<I>(PhantomData<I>);
impl<I: Interner> InferCtxtLike for NoInfcx<I> {
type Interner = I;
fn interner(&self) -> Self::Interner {
unreachable!()
}
fn universe_of_ty(&self, _ty: TyVid) -> Option<UniverseIndex> {
None
}
fn universe_of_lt(&self, _lt: RegionVid) -> Option<UniverseIndex> {
None
}
fn universe_of_ct(&self, _ct: ConstVid) -> Option<UniverseIndex> {
None
}
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> I::Ty {
panic!("cannot resolve {vid:?}")
}
fn opportunistic_resolve_int_var(&self, vid: IntVid) -> I::Ty {
panic!("cannot resolve {vid:?}")
}
fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> I::Ty {
panic!("cannot resolve {vid:?}")
}
fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> I::Const {
panic!("cannot resolve {vid:?}")
}
fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> I::Const {
panic!("cannot resolve {vid:?}")
}
fn opportunistic_resolve_lt_var(&self, vid: crate::RegionVid) -> I::Region {
panic!("cannot resolve {vid:?}")
}
fn defining_opaque_types(&self) -> I::DefiningOpaqueTypes {
Default::default()
}
}
pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result;
}
impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
<T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f)
}
}
impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
match f.alternate() {
true => {
write!(f, "[\n")?;
for element in this.data.iter() {
write!(f, "{:?},\n", &this.wrap(element))?;
}
write!(f, "]")
}
false => {
write!(f, "[")?;
if this.data.len() > 0 {
for element in &this.data[..(this.data.len() - 1)] {
write!(f, "{:?}, ", &this.wrap(element))?;
}
if let Some(element) = this.data.last() {
write!(f, "{:?}", &this.wrap(element))?;
}
}
write!(f, "]")
}
}
}
}
pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> {
pub data: T,
pub infcx: &'a Infcx,
}
impl<Infcx: InferCtxtLike, T: Copy> Copy for WithInfcx<'_, Infcx, T> {}
impl<Infcx: InferCtxtLike, T: Clone> Clone for WithInfcx<'_, Infcx, T> {
fn clone(&self) -> Self {
Self { data: self.data.clone(), infcx: self.infcx }
}
}
impl<'a, I: Interner, T> WithInfcx<'a, NoInfcx<I>, T> {
pub fn with_no_infcx(data: T) -> Self {
Self { data, infcx: &NoInfcx(PhantomData) }
}
}
impl<'a, Infcx: InferCtxtLike, T> WithInfcx<'a, Infcx, T> {
pub fn new(data: T, infcx: &'a Infcx) -> Self {
Self { data, infcx }
}
pub fn wrap<U>(self, u: U) -> WithInfcx<'a, Infcx, U> {
WithInfcx { data: u, infcx: self.infcx }
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> WithInfcx<'a, Infcx, U> {
WithInfcx { data: f(self.data), infcx: self.infcx }
}
pub fn as_ref(&self) -> WithInfcx<'a, Infcx, &T> {
WithInfcx { data: &self.data, infcx: self.infcx }
}
}
impl<Infcx: InferCtxtLike, T: DebugWithInfcx<Infcx::Interner>> fmt::Debug
for WithInfcx<'_, Infcx, T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DebugWithInfcx::fmt(self.as_ref(), f)
}
}

View File

@ -12,11 +12,11 @@ use rustc_ast_ir::Mutability;
use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::fold::{TypeFoldable, TypeSuperFoldable};
use crate::relate::Relate; use crate::relate::Relate;
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
pub trait Ty<I: Interner<Ty = Self>>: pub trait Ty<I: Interner<Ty = Self>>:
Copy Copy
+ DebugWithInfcx<I> + Debug
+ Hash + Hash
+ Eq + Eq
+ Into<I::GenericArg> + Into<I::GenericArg>
@ -116,7 +116,7 @@ pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + TypeVis
pub trait Region<I: Interner<Region = Self>>: pub trait Region<I: Interner<Region = Self>>:
Copy Copy
+ DebugWithInfcx<I> + Debug
+ Hash + Hash
+ Eq + Eq
+ Into<I::GenericArg> + Into<I::GenericArg>
@ -134,7 +134,7 @@ pub trait Region<I: Interner<Region = Self>>:
pub trait Const<I: Interner<Const = Self>>: pub trait Const<I: Interner<Const = Self>>:
Copy Copy
+ DebugWithInfcx<I> + Debug
+ Hash + Hash
+ Eq + Eq
+ Into<I::GenericArg> + Into<I::GenericArg>
@ -166,7 +166,7 @@ pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
pub trait GenericArgs<I: Interner<GenericArgs = Self>>: pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
Copy Copy
+ DebugWithInfcx<I> + Debug
+ Hash + Hash
+ Eq + Eq
+ IntoIterator<Item = I::GenericArg> + IntoIterator<Item = I::GenericArg>

View File

@ -9,7 +9,7 @@ use crate::ir_print::IrPrint;
use crate::relate::Relate; use crate::relate::Relate;
use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::solve::inspect::CanonicalGoalEvaluationStep;
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{self as ty, DebugWithInfcx}; use crate::{self as ty};
pub trait Interner: pub trait Interner:
Sized Sized
@ -32,7 +32,7 @@ pub trait Interner:
type GenericArgs: GenericArgs<Self>; type GenericArgs: GenericArgs<Self>;
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
type GenericArg: Copy type GenericArg: Copy
+ DebugWithInfcx<Self> + Debug
+ Hash + Hash
+ Eq + Eq
+ IntoKind<Kind = ty::GenericArgKind<Self>> + IntoKind<Kind = ty::GenericArgKind<Self>>
@ -74,9 +74,9 @@ pub trait Interner:
// Things stored inside of tys // Things stored inside of tys
type ErrorGuaranteed: Copy + Debug + Hash + Eq; type ErrorGuaranteed: Copy + Debug + Hash + Eq;
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>; type BoundExistentialPredicates: Copy + Debug + Hash + Eq + Relate<Self>;
type AllocId: Copy + Debug + Hash + Eq; type AllocId: Copy + Debug + Hash + Eq;
type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self> + Relate<Self>; type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>; type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>;
type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>; type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>;
@ -86,7 +86,7 @@ pub trait Interner:
type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
type ValueConst: Copy + Debug + Hash + Eq; type ValueConst: Copy + Debug + Hash + Eq;
type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>; type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>;
// Kinds of regions // Kinds of regions
type Region: Region<Self>; type Region: Region<Self>;

View File

@ -42,7 +42,6 @@ mod macros;
mod binder; mod binder;
mod canonical; mod canonical;
mod const_kind; mod const_kind;
mod debug;
mod flags; mod flags;
mod generic_arg; mod generic_arg;
mod infcx; mod infcx;
@ -59,7 +58,6 @@ pub use canonical::*;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
pub use codec::*; pub use codec::*;
pub use const_kind::*; pub use const_kind::*;
pub use debug::{DebugWithInfcx, WithInfcx};
pub use flags::*; pub use flags::*;
pub use generic_arg::*; pub use generic_arg::*;
pub use infcx::InferCtxtLike; pub use infcx::InferCtxtLike;

View File

@ -9,7 +9,7 @@ use crate::inherent::*;
use crate::lift::Lift; use crate::lift::Lift;
use crate::upcast::Upcast; use crate::upcast::Upcast;
use crate::visit::TypeVisitableExt as _; use crate::visit::TypeVisitableExt as _;
use crate::{self as ty, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use crate::{self as ty, Interner};
/// `A: 'region` /// `A: 'region`
#[derive(derivative::Derivative)] #[derive(derivative::Derivative)]
@ -248,16 +248,6 @@ pub enum ExistentialPredicate<I: Interner> {
AutoTrait(I::DefId), AutoTrait(I::DefId),
} }
// FIXME: Implement this the right way after
impl<I: Interner> DebugWithInfcx<I> for ExistentialPredicate<I> {
fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = I>>(
this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(&this.data, f)
}
}
impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> { impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`), /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
@ -459,7 +449,8 @@ impl AliasTermKind {
Copy(bound = ""), Copy(bound = ""),
Hash(bound = ""), Hash(bound = ""),
PartialEq(bound = ""), PartialEq(bound = ""),
Eq(bound = "") Eq(bound = ""),
Debug(bound = "")
)] )]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
@ -493,23 +484,6 @@ pub struct AliasTerm<I: Interner> {
_use_alias_term_new_instead: (), _use_alias_term_new_instead: (),
} }
impl<I: Interner> std::fmt::Debug for AliasTerm<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<I: Interner> DebugWithInfcx<I> for AliasTerm<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
f.debug_struct("AliasTerm")
.field("args", &this.map(|data| data.args))
.field("def_id", &this.data.def_id)
.finish()
}
}
impl<I: Interner> AliasTerm<I> { impl<I: Interner> AliasTerm<I> {
pub fn new( pub fn new(
interner: I, interner: I,

View File

@ -4,7 +4,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use std::fmt; use std::fmt;
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use crate::{DebruijnIndex, Interner};
use self::RegionKind::*; use self::RegionKind::*;
@ -18,18 +18,6 @@ rustc_index::newtype_index! {
pub struct RegionVid {} pub struct RegionVid {}
} }
impl<I: Interner> DebugWithInfcx<I> for RegionVid {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match this.infcx.universe_of_lt(*this.data) {
Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
None => write!(f, "{:?}", this.data),
}
}
}
/// Representation of regions. Note that the NLL checker uses a distinct /// Representation of regions. Note that the NLL checker uses a distinct
/// representation of regions. For this reason, it internally replaces all the /// representation of regions. For this reason, it internally replaces all the
/// regions with inference variables -- the index of the variable is then used /// regions with inference variables -- the index of the variable is then used
@ -230,12 +218,9 @@ impl<I: Interner> PartialEq for RegionKind<I> {
} }
} }
impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { impl<I: Interner> fmt::Debug for RegionKind<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>( fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
this: WithInfcx<'_, Infcx, &Self>, match self {
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match this.data {
ReEarlyParam(data) => write!(f, "{data:?}"), ReEarlyParam(data) => write!(f, "{data:?}"),
ReBound(binder_id, bound_region) => { ReBound(binder_id, bound_region) => {
@ -247,7 +232,7 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
ReStatic => f.write_str("'static"), ReStatic => f.write_str("'static"),
ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)), ReVar(vid) => write!(f, "{:?}", &vid),
RePlaceholder(placeholder) => write!(f, "{placeholder:?}"), RePlaceholder(placeholder) => write!(f, "{placeholder:?}"),
@ -260,11 +245,6 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
} }
} }
} }
impl<I: Interner> fmt::Debug for RegionKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
// This is not a derived impl because a derive would require `I: HashStable` // This is not a derived impl because a derive would require `I: HashStable`

View File

@ -10,7 +10,7 @@ use std::fmt;
pub use self::closure::*; pub use self::closure::*;
use self::TyKind::*; use self::TyKind::*;
use crate::inherent::*; use crate::inherent::*;
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use crate::{self as ty, DebruijnIndex, Interner};
use rustc_ast_ir::Mutability; use rustc_ast_ir::Mutability;
@ -341,12 +341,10 @@ impl<I: Interner> PartialEq for TyKind<I> {
} }
} }
impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { // This is manually implemented because a derive would require `I: Debug`
fn fmt<Infcx: InferCtxtLike<Interner = I>>( impl<I: Interner> fmt::Debug for TyKind<I> {
this: WithInfcx<'_, Infcx, &Self>, fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f: &mut fmt::Formatter<'_>, match self {
) -> fmt::Result {
match this.data {
Bool => write!(f, "bool"), Bool => write!(f, "bool"),
Char => write!(f, "char"), Char => write!(f, "char"),
Int(i) => write!(f, "{i:?}"), Int(i) => write!(f, "{i:?}"),
@ -369,27 +367,23 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
} }
Foreign(d) => f.debug_tuple("Foreign").field(d).finish(), Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
Str => write!(f, "str"), Str => write!(f, "str"),
Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)), Array(t, c) => write!(f, "[{:?}; {:?}]", &t, &c),
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)), Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &t, &p),
Slice(t) => write!(f, "[{:?}]", &this.wrap(t)), Slice(t) => write!(f, "[{:?}]", &t),
RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), this.wrap(ty)), RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), ty),
Ref(r, t, m) => write!(f, "&{:?} {}{:?}", this.wrap(r), m.prefix_str(), this.wrap(t)), Ref(r, t, m) => write!(f, "&{:?} {}{:?}", r, m.prefix_str(), t),
FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&this.wrap(s)).finish(), FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&s).finish(),
FnPtr(s) => write!(f, "{:?}", &this.wrap(s)), FnPtr(s) => write!(f, "{:?}", &s),
Dynamic(p, r, repr) => match repr { Dynamic(p, r, repr) => match repr {
DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &this.wrap(p), &this.wrap(r)), DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &p, &r),
DynKind::DynStar => { DynKind::DynStar => {
write!(f, "dyn* {:?} + {:?}", &this.wrap(p), &this.wrap(r)) write!(f, "dyn* {:?} + {:?}", &p, &r)
} }
}, },
Closure(d, s) => f.debug_tuple("Closure").field(d).field(&this.wrap(s)).finish(), Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(),
CoroutineClosure(d, s) => { CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&s).finish(),
f.debug_tuple("CoroutineClosure").field(d).field(&this.wrap(s)).finish() Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&s).finish(),
} CoroutineWitness(d, s) => f.debug_tuple("CoroutineWitness").field(d).field(&s).finish(),
Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).finish(),
CoroutineWitness(d, s) => {
f.debug_tuple("CoroutineWitness").field(d).field(&this.wrap(s)).finish()
}
Never => write!(f, "!"), Never => write!(f, "!"),
Tuple(t) => { Tuple(t) => {
write!(f, "(")?; write!(f, "(")?;
@ -398,7 +392,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
if count > 0 { if count > 0 {
write!(f, ", ")?; write!(f, ", ")?;
} }
write!(f, "{:?}", &this.wrap(ty))?; write!(f, "{:?}", &ty)?;
count += 1; count += 1;
} }
// unary tuples need a trailing comma // unary tuples need a trailing comma
@ -407,23 +401,16 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
} }
write!(f, ")") write!(f, ")")
} }
Alias(i, a) => f.debug_tuple("Alias").field(i).field(&this.wrap(a)).finish(), Alias(i, a) => f.debug_tuple("Alias").field(i).field(&a).finish(),
Param(p) => write!(f, "{p:?}"), Param(p) => write!(f, "{p:?}"),
Bound(d, b) => crate::debug_bound_var(f, *d, b), Bound(d, b) => crate::debug_bound_var(f, *d, b),
Placeholder(p) => write!(f, "{p:?}"), Placeholder(p) => write!(f, "{p:?}"),
Infer(t) => write!(f, "{:?}", this.wrap(t)), Infer(t) => write!(f, "{:?}", t),
TyKind::Error(_) => write!(f, "{{type error}}"), TyKind::Error(_) => write!(f, "{{type error}}"),
} }
} }
} }
// This is manually implemented because a derive would require `I: Debug`
impl<I: Interner> fmt::Debug for TyKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
/// Represents the projection of an associated, opaque, or lazy-type-alias type. /// Represents the projection of an associated, opaque, or lazy-type-alias type.
/// ///
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`. /// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
@ -435,7 +422,8 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
Copy(bound = ""), Copy(bound = ""),
Hash(bound = ""), Hash(bound = ""),
PartialEq(bound = ""), PartialEq(bound = ""),
Eq(bound = "") Eq(bound = ""),
Debug(bound = "")
)] )]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
@ -555,23 +543,6 @@ impl<I: Interner> AliasTy<I> {
} }
} }
impl<I: Interner> fmt::Debug for AliasTy<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
f.debug_struct("AliasTy")
.field("args", &this.map(|data| data.args))
.field("def_id", &this.data.def_id)
.finish()
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
pub enum IntTy { pub enum IntTy {
@ -968,24 +939,6 @@ impl fmt::Debug for InferTy {
} }
} }
impl<I: Interner> DebugWithInfcx<I> for InferTy {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
match this.data {
InferTy::TyVar(vid) => {
if let Some(universe) = this.infcx.universe_of_ty(*vid) {
write!(f, "?{}_{}t", vid.index(), universe.index())
} else {
write!(f, "{:?}", this.data)
}
}
_ => write!(f, "{:?}", this.data),
}
}
}
#[derive(derivative::Derivative)] #[derive(derivative::Derivative)]
#[derivative( #[derivative(
Clone(bound = ""), Clone(bound = ""),
@ -1078,15 +1031,7 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> {
impl<I: Interner> fmt::Debug for FnSig<I> { impl<I: Interner> fmt::Debug for FnSig<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f) let sig = self;
}
}
impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
let sig = this.data;
let FnSig { inputs_and_output: _, c_variadic, safety, abi } = sig; let FnSig { inputs_and_output: _, c_variadic, safety, abi } = sig;
write!(f, "{}", safety.prefix_str())?; write!(f, "{}", safety.prefix_str())?;
@ -1100,7 +1045,7 @@ impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
if i > 0 { if i > 0 {
write!(f, ", ")?; write!(f, ", ")?;
} }
write!(f, "{:?}", &this.wrap(ty))?; write!(f, "{:?}", &ty)?;
} }
if *c_variadic { if *c_variadic {
if inputs.is_empty() { if inputs.is_empty() {
@ -1113,7 +1058,7 @@ impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
match output.kind() { match output.kind() {
Tuple(list) if list.is_empty() => Ok(()), Tuple(list) if list.is_empty() => Ok(()),
_ => write!(f, " -> {:?}", &this.wrap(sig.output())), _ => write!(f, " -> {:?}", sig.output()),
} }
} }
} }

View File

@ -404,9 +404,9 @@ fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option<I::Reifi
where where
I: tags::Type<'a>, I: tags::Type<'a>,
{ {
let mut tagged = TaggedOption::<'a, I>(None); let mut tagged = Tagged { tag_id: TypeId::of::<I>(), value: TaggedOption::<'a, I>(None) };
err.provide(tagged.as_request()); err.provide(tagged.as_request());
tagged.0 tagged.value.0
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -507,16 +507,9 @@ where
/// ///
#[unstable(feature = "error_generic_member_access", issue = "99301")] #[unstable(feature = "error_generic_member_access", issue = "99301")]
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 #[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
pub struct Request<'a>(dyn Erased<'a> + 'a); pub struct Request<'a>(Tagged<dyn Erased<'a> + 'a>);
impl<'a> Request<'a> { impl<'a> Request<'a> {
/// Create a new `&mut Request` from a `&mut dyn Erased` trait object.
fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Request<'a> {
// SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Request<'a>` is safe since
// `Request` is repr(transparent).
unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Request<'a>) }
}
/// Provide a value or other type with only static lifetimes. /// Provide a value or other type with only static lifetimes.
/// ///
/// # Examples /// # Examples
@ -940,27 +933,28 @@ pub(crate) mod tags {
#[repr(transparent)] #[repr(transparent)]
pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>); pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>);
impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> { impl<'a, I: tags::Type<'a>> Tagged<TaggedOption<'a, I>> {
pub(crate) fn as_request(&mut self) -> &mut Request<'a> { pub(crate) fn as_request(&mut self) -> &mut Request<'a> {
Request::new(self as &mut (dyn Erased<'a> + 'a)) let erased = self as &mut Tagged<dyn Erased<'a> + 'a>;
// SAFETY: transmuting `&mut Tagged<dyn Erased<'a> + 'a>` to `&mut Request<'a>` is safe since
// `Request` is repr(transparent).
unsafe { &mut *(erased as *mut Tagged<dyn Erased<'a>> as *mut Request<'a>) }
} }
} }
/// Represents a type-erased but identifiable object. /// Represents a type-erased but identifiable object.
/// ///
/// This trait is exclusively implemented by the `TaggedOption` type. /// This trait is exclusively implemented by the `TaggedOption` type.
unsafe trait Erased<'a>: 'a { unsafe trait Erased<'a>: 'a {}
/// The `TypeId` of the erased type.
fn tag_id(&self) -> TypeId; unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {}
struct Tagged<E: ?Sized> {
tag_id: TypeId,
value: E,
} }
unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> { impl<'a> Tagged<dyn Erased<'a> + 'a> {
fn tag_id(&self) -> TypeId {
TypeId::of::<I>()
}
}
impl<'a> dyn Erased<'a> + 'a {
/// Returns some reference to the dynamic value if it is tagged with `I`, /// Returns some reference to the dynamic value if it is tagged with `I`,
/// or `None` otherwise. /// or `None` otherwise.
#[inline] #[inline]
@ -968,9 +962,9 @@ impl<'a> dyn Erased<'a> + 'a {
where where
I: tags::Type<'a>, I: tags::Type<'a>,
{ {
if self.tag_id() == TypeId::of::<I>() { if self.tag_id == TypeId::of::<I>() {
// SAFETY: Just checked whether we're pointing to an I. // SAFETY: Just checked whether we're pointing to an I.
Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() }) Some(&unsafe { &*(self as *const Self).cast::<Tagged<TaggedOption<'a, I>>>() }.value)
} else { } else {
None None
} }
@ -983,9 +977,12 @@ impl<'a> dyn Erased<'a> + 'a {
where where
I: tags::Type<'a>, I: tags::Type<'a>,
{ {
if self.tag_id() == TypeId::of::<I>() { if self.tag_id == TypeId::of::<I>() {
// SAFETY: Just checked whether we're pointing to an I. Some(
Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() }) // SAFETY: Just checked whether we're pointing to an I.
&mut unsafe { &mut *(self as *mut Self).cast::<Tagged<TaggedOption<'a, I>>>() }
.value,
)
} else { } else {
None None
} }

View File

@ -29,9 +29,8 @@ impl<'a> PanicInfo<'a> {
PanicInfo { location, message, can_unwind, force_no_backtrace } PanicInfo { location, message, can_unwind, force_no_backtrace }
} }
/// If the `panic!` macro from the `core` crate (not from `std`) /// The message that was given to the `panic!` macro,
/// was used with a formatting string and some additional arguments, /// ready to be formatted with e.g. [`fmt::write`].
/// returns that message ready to be used for example with [`fmt::write`]
#[must_use] #[must_use]
#[unstable(feature = "panic_info_message", issue = "66745")] #[unstable(feature = "panic_info_message", issue = "66745")]
pub fn message(&self) -> fmt::Arguments<'_> { pub fn message(&self) -> fmt::Arguments<'_> {
@ -72,7 +71,7 @@ impl<'a> PanicInfo<'a> {
/// Returns the payload associated with the panic. /// Returns the payload associated with the panic.
/// ///
/// On `core::panic::PanicInfo`, this method never returns anything useful. /// On this type, `core::panic::PanicInfo`, this method never returns anything useful.
/// It only exists because of compatibility with [`std::panic::PanicHookInfo`], /// It only exists because of compatibility with [`std::panic::PanicHookInfo`],
/// which used to be the same type. /// which used to be the same type.
/// ///
@ -80,7 +79,7 @@ impl<'a> PanicInfo<'a> {
/// ///
/// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html /// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html
/// [`std::panic::PanicHookInfo::payload`]: ../../std/panic/struct.PanicHookInfo.html#method.payload /// [`std::panic::PanicHookInfo::payload`]: ../../std/panic/struct.PanicHookInfo.html#method.payload
#[deprecated(since = "1.77.0", note = "this never returns anything useful")] #[deprecated(since = "1.81.0", note = "this never returns anything useful")]
#[stable(feature = "panic_hooks", since = "1.10.0")] #[stable(feature = "panic_hooks", since = "1.10.0")]
#[allow(deprecated, deprecated_in_future)] #[allow(deprecated, deprecated_in_future)]
pub fn payload(&self) -> &(dyn crate::any::Any + Send) { pub fn payload(&self) -> &(dyn crate::any::Any + Send) {

View File

@ -244,7 +244,11 @@ mod arch {
pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
} }
#[cfg(target_arch = "aarch64")] #[cfg(any(
target_arch = "aarch64",
// Arm64EC is Windows-only, but docs are always build as Linux, so re-use AArch64 for Arm64EC.
all(doc, target_arch = "arm64ec")
))]
mod arch { mod arch {
use crate::os::raw::{c_int, c_long}; use crate::os::raw::{c_int, c_long};

View File

@ -202,10 +202,7 @@ impl fmt::Display for PanicHookInfo<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("panicked at ")?; formatter.write_str("panicked at ")?;
self.location.fmt(formatter)?; self.location.fmt(formatter)?;
if let Some(payload) = self.payload.downcast_ref::<&'static str>() { if let Some(payload) = self.payload_as_str() {
formatter.write_str(":\n")?;
formatter.write_str(payload)?;
} else if let Some(payload) = self.payload.downcast_ref::<String>() {
formatter.write_str(":\n")?; formatter.write_str(":\n")?;
formatter.write_str(payload)?; formatter.write_str(payload)?;
} }

View File

@ -428,6 +428,7 @@ auto:
RUST_CONFIGURE_ARGS: >- RUST_CONFIGURE_ARGS: >-
--build=x86_64-pc-windows-msvc --build=x86_64-pc-windows-msvc
--host=aarch64-pc-windows-msvc --host=aarch64-pc-windows-msvc
--target=aarch64-pc-windows-msvc,arm64ec-pc-windows-msvc
--enable-full-tools --enable-full-tools
--enable-profiler --enable-profiler
SCRIPT: python x.py dist bootstrap --include-default-paths SCRIPT: python x.py dist bootstrap --include-default-paths

View File

@ -146,6 +146,7 @@ target | std | notes
[`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android [`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android
`arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3 `arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
`arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat `arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat
[`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian [`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat [`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23) `armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
@ -240,7 +241,6 @@ target | std | host | notes
-------|:---:|:----:|------- -------|:---:|:----:|-------
[`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS [`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
[`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md) | ✓ | ✓ | ARM64e Apple Darwin [`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md) | ✓ | ✓ | ARM64e Apple Darwin
[`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ? | | Arm64EC Windows MSVC
[`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | | Apple Catalyst on ARM64 [`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | | Apple Catalyst on ARM64
[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS [`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS
[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS Simulator [`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS Simulator

View File

@ -1,6 +1,6 @@
# `arm64ec-pc-windows-msvc` # `arm64ec-pc-windows-msvc`
**Tier: 3** **Tier: 2**
Arm64EC ("Emulation Compatible") for mixed architecture (AArch64 and x86_64) Arm64EC ("Emulation Compatible") for mixed architecture (AArch64 and x86_64)
applications on AArch64 Windows 11. See <https://learn.microsoft.com/en-us/windows/arm/arm64ec>. applications on AArch64 Windows 11. See <https://learn.microsoft.com/en-us/windows/arm/arm64ec>.
@ -21,6 +21,9 @@ Only supported backend is LLVM 18 or above:
* 18.1.4 fixed linking issue for some intrinsics implemented in * 18.1.4 fixed linking issue for some intrinsics implemented in
`compiler_builtins`. `compiler_builtins`.
Visual Studio 2022 (or above) with the "ARM64/ARM64EC built tools" component and
the Windows 11 SDK are required.
### Reusing code from other architectures - x86_64 or AArch64? ### Reusing code from other architectures - x86_64 or AArch64?
Arm64EC uses `arm64ec` as its `target_arch`, but it is possible to reuse Arm64EC uses `arm64ec` as its `target_arch`, but it is possible to reuse
@ -62,10 +65,8 @@ target = [ "arm64ec-pc-windows-msvc" ]
## Building Rust programs ## Building Rust programs
Rust does not yet ship pre-compiled artifacts for this target. To compile for These targets are distributed through `rustup`, and otherwise require no
this target, you will either need to build Rust with the target enabled (see special configuration.
"Building the target" above), or build your own copy using `build-std` or
similar.
## Testing ## Testing

View File

@ -71,6 +71,7 @@ static TARGETS: &[&str] = &[
"arm-unknown-linux-gnueabihf", "arm-unknown-linux-gnueabihf",
"arm-unknown-linux-musleabi", "arm-unknown-linux-musleabi",
"arm-unknown-linux-musleabihf", "arm-unknown-linux-musleabihf",
"arm64ec-pc-windows-msvc",
"armv5te-unknown-linux-gnueabi", "armv5te-unknown-linux-gnueabi",
"armv5te-unknown-linux-musleabi", "armv5te-unknown-linux-musleabi",
"armv7-linux-androideabi", "armv7-linux-androideabi",

View File

@ -1,5 +1,5 @@
// Validation stops this too early. // Validation and SB stop this too early.
//@compile-flags: -Zmiri-disable-validation //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
trait T1 { trait T1 {
#[allow(dead_code)] #[allow(dead_code)]

View File

@ -0,0 +1,40 @@
#![feature(ptr_metadata)]
// This test is the result of minimizing the `emplacable` crate to reproduce
// <https://github.com/rust-lang/miri/issues/3541>.
use std::{ops::FnMut, ptr::Pointee};
pub type EmplacerFn<'a, T> = dyn for<'b> FnMut(<T as Pointee>::Metadata) + 'a;
#[repr(transparent)]
pub struct Emplacer<'a, T>(EmplacerFn<'a, T>)
where
T: ?Sized;
impl<'a, T> Emplacer<'a, T>
where
T: ?Sized,
{
pub unsafe fn from_fn<'b>(emplacer_fn: &'b mut EmplacerFn<'a, T>) -> &'b mut Self {
// This used to trigger:
// constructing invalid value: wrong trait in wide pointer vtable: expected
// `std::ops::FnMut(<[std::boxed::Box<i32>] as std::ptr::Pointee>::Metadata)`, but encountered
// `std::ops::FnMut<(usize,)>`.
unsafe { &mut *((emplacer_fn as *mut EmplacerFn<'a, T>) as *mut Self) }
}
}
pub fn box_new_with<T>()
where
T: ?Sized,
{
let emplacer_closure = &mut |_meta| {
unreachable!();
};
unsafe { Emplacer::<T>::from_fn(emplacer_closure) };
}
fn main() {
box_new_with::<[Box<i32>]>();
}

@ -1 +1 @@
Subproject commit 72daa50ce2350f5a9b5ae6dc3ad6babccd14ec0a Subproject commit c64bb60dd1636922b1ccbb82867bed934a99dbcb

View File

@ -0,0 +1,13 @@
Function name: assert_ne::main
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 08, 01, 03, 1c, 05, 04, 0d, 00, 13, 02, 02, 0d, 00, 13, 09, 03, 05, 01, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 4
- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28)
- Code(Counter(1)) at (prev + 4, 13) to (start + 0, 19)
- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19)
= (c0 - c1)
- Code(Counter(2)) at (prev + 3, 5) to (start + 1, 2)

View File

@ -0,0 +1,23 @@
LL| |//@ edition: 2021
LL| |
LL| |use core::hint::black_box;
LL| |
LL| |#[derive(Debug, PartialEq)]
LL| |struct Foo(u32);
LL| |
LL| 1|fn main() {
LL| 1| assert_ne!(
LL| 1| Foo(5), // Make sure this expression's span isn't lost.
LL| 1| if black_box(false) {
LL| 0| Foo(0) //
LL| | } else {
LL| 1| Foo(1) //
LL| | }
LL| | );
LL| 1| ()
LL| 1|}
LL| |
LL| |// This test is a short fragment extracted from `issue-84561.rs`, highlighting
LL| |// a particular span of code that can easily be lost if overlapping spans are
LL| |// processed incorrectly.

View File

@ -0,0 +1,22 @@
//@ edition: 2021
use core::hint::black_box;
#[derive(Debug, PartialEq)]
struct Foo(u32);
fn main() {
assert_ne!(
Foo(5), // Make sure this expression's span isn't lost.
if black_box(false) {
Foo(0) //
} else {
Foo(1) //
}
);
()
}
// This test is a short fragment extracted from `issue-84561.rs`, highlighting
// a particular span of code that can easily be lost if overlapping spans are
// processed incorrectly.

View File

@ -0,0 +1,14 @@
Function name: loop_break::main
Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 03, 01, 00, 0b, 03, 02, 0c, 00, 27, 01, 01, 0d, 00, 12, 05, 01, 0a, 00, 0b, 01, 02, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
Number of file 0 mappings: 5
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 11)
- Code(Expression(0, Add)) at (prev + 2, 12) to (start + 0, 39)
= (c0 + c1)
- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18)
- Code(Counter(1)) at (prev + 1, 10) to (start + 0, 11)
- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)

View File

@ -0,0 +1,14 @@
LL| |//@ edition: 2021
LL| |
LL| 1|fn main() {
LL| | loop {
LL| 1| if core::hint::black_box(true) {
LL| 1| break;
LL| 0| }
LL| | }
LL| 1|}
LL| |
LL| |// This test is a lightly-modified version of `tests/mir-opt/coverage/instrument_coverage.rs`.
LL| |// If this test needs to be blessed, then the mir-opt version probably needs to
LL| |// be blessed too!

View File

@ -0,0 +1,13 @@
//@ edition: 2021
fn main() {
loop {
if core::hint::black_box(true) {
break;
}
}
}
// This test is a lightly-modified version of `tests/mir-opt/coverage/instrument_coverage.rs`.
// If this test needs to be blessed, then the mir-opt version probably needs to
// be blessed too!

View File

@ -5,12 +5,15 @@
ty: Coroutine( ty: Coroutine(
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
[ [
(), (),
std::future::ResumeTy, std::future::ResumeTy,
(), (),
(), (),
CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []), CoroutineWitness(
(), DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
[],
),
(),
], ],
), ),
source_info: SourceInfo { source_info: SourceInfo {
@ -23,12 +26,15 @@
ty: Coroutine( ty: Coroutine(
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
[ [
(), (),
std::future::ResumeTy, std::future::ResumeTy,
(), (),
(), (),
CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []), CoroutineWitness(
(), DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
[],
),
(),
], ],
), ),
source_info: SourceInfo { source_info: SourceInfo {

View File

@ -9,7 +9,7 @@
+ coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) }; + coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) };
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11; + coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11;
+ coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:11:5 - 12:17; + coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:12:12 - 12:17;
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18; + coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18;
+ coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11; + coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11;
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2; + coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2;

View File

@ -0,0 +1,22 @@
enum E {
A,
B,
C,
}
fn foo(e: E) {
let bar;
match e {
E::A if true => return,
E::A => return,
E::B => {}
E::C => {
bar = 5;
}
}
let _baz = bar; //~ ERROR E0381
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0381]: used binding `bar` is possibly-uninitialized
--> $DIR/uninitalized-in-match-arm-issue-126133.rs:19:16
|
LL | let bar;
| --- binding declared here but left uninitialized
...
LL | E::B => {}
| ---- if this pattern is matched, `bar` is not initialized
...
LL | let _baz = bar;
| ^^^ `bar` used here but it is possibly-uninitialized
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0381`.

View File

@ -1,7 +1,7 @@
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
--> $DIR/associated-type.rs:31:1 --> $DIR/associated-type.rs:31:1
| |

View File

@ -1,11 +1,11 @@
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)`
--> $DIR/associated-type.rs:31:1 --> $DIR/associated-type.rs:31:1
| |

View File

@ -0,0 +1,20 @@
// Given an anon const `a`: `{ N }` and some anon const `b` which references the
// first anon const: `{ [1; a] }`. `b` should not have any generics as it is not
// a simple `N` argument nor is it a repeat expr count.
//
// On the other hand `b` *is* a repeat expr count and so it should inherit its
// parents generics as part of the `const_evaluatable_unchecked` fcw (#76200).
//
// In this specific case however `b`'s parent should be `a` and so it should wind
// up not having any generics after all. If `a` were to inherit its generics from
// the enclosing item then the reference to `a` from `b` would contain generic
// parameters not usable by `b` which would cause us to ICE.
fn bar<const N: usize>() {}
fn foo<const N: usize>() {
bar::<{ [1; N] }>();
//~^ ERROR: generic parameters may not be used in const operations
}
fn main() {}

View File

@ -0,0 +1,11 @@
error: generic parameters may not be used in const operations
--> $DIR/repeat_expr_hack_gives_right_generics.rs:16:17
|
LL | bar::<{ [1; N] }>();
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
error: aborting due to 1 previous error

View File

@ -1,5 +1,5 @@
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () }
error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
--> $DIR/structually-relate-aliases.rs:13:36 --> $DIR/structually-relate-aliases.rs:13:36
| |

View File

@ -25,10 +25,10 @@ help: this trait has no implementations, consider adding one
LL | trait ToUnit<'a> { LL | trait ToUnit<'a> {
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)` error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)`
--> $DIR/issue-118950-root-region.rs:19:1 --> $DIR/issue-118950-root-region.rs:19:1
| |