mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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:
commit
1d43fbbc73
@ -557,8 +557,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// for the branching codepaths that aren't covered, to point at them.
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body = map.body_owned_by(self.mir_def_id());
|
||||
|
||||
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
|
||||
let mut visitor =
|
||||
ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
|
||||
visitor.visit_body(&body);
|
||||
|
||||
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
|
||||
/// function expressions looking for branching code paths that *do not* initialize the binding.
|
||||
struct ConditionVisitor<'b> {
|
||||
struct ConditionVisitor<'b, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
spans: &'b [Span],
|
||||
name: &'b str,
|
||||
errors: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
||||
impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||
match ex.kind {
|
||||
hir::ExprKind::If(cond, body, None) => {
|
||||
@ -4464,6 +4465,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
||||
),
|
||||
));
|
||||
} else if let Some(guard) = &arm.guard {
|
||||
if matches!(
|
||||
self.tcx.hir_node(arm.body.hir_id),
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
self.errors.push((
|
||||
arm.pat.span.to(guard.span),
|
||||
format!(
|
||||
@ -4473,6 +4480,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
||||
),
|
||||
));
|
||||
} else {
|
||||
if matches!(
|
||||
self.tcx.hir_node(arm.body.hir_id),
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
self.errors.push((
|
||||
arm.pat.span,
|
||||
format!(
|
||||
|
@ -387,7 +387,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
|
||||
(&ty::Array(_, length), &ty::Slice(_)) => {
|
||||
let ptr = self.read_pointer(src)?;
|
||||
// u64 cast is from usize to u64, which is always good
|
||||
let val = Immediate::new_slice(
|
||||
ptr,
|
||||
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_data.to_pointer(self)?;
|
||||
let old_vptr = old_vptr.to_pointer(self)?;
|
||||
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
|
||||
if old_trait != data_a.principal() {
|
||||
throw_ub!(InvalidVTableTrait {
|
||||
expected_trait: data_a,
|
||||
vtable_trait: old_trait,
|
||||
});
|
||||
}
|
||||
let ty = self.get_ptr_vtable_ty(old_vptr, Some(data_a))?;
|
||||
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
|
||||
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
||||
}
|
||||
|
@ -765,10 +765,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
}
|
||||
Ok(Some((full_size, full_align)))
|
||||
}
|
||||
ty::Dynamic(_, _, ty::Dyn) => {
|
||||
ty::Dynamic(expected_trait, _, ty::Dyn) => {
|
||||
let vtable = metadata.unwrap_meta().to_pointer(self)?;
|
||||
// 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 => {
|
||||
|
@ -432,12 +432,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
|
||||
sym::vtable_size => {
|
||||
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)?;
|
||||
}
|
||||
sym::vtable_align => {
|
||||
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)?;
|
||||
}
|
||||
|
||||
|
@ -867,19 +867,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
.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,
|
||||
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);
|
||||
let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
|
||||
if offset.bytes() != 0 {
|
||||
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
|
||||
}
|
||||
match self.tcx.try_get_global_alloc(alloc_id) {
|
||||
Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)),
|
||||
_ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))),
|
||||
let Some(GlobalAlloc::VTable(ty, vtable_trait)) = self.tcx.try_get_global_alloc(alloc_id)
|
||||
else {
|
||||
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> {
|
||||
|
@ -9,7 +9,6 @@ use tracing::{instrument, trace};
|
||||
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
@ -1018,54 +1017,6 @@ where
|
||||
let layout = self.layout_of(raw.ty)?;
|
||||
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.
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use either::Either;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::trace;
|
||||
|
||||
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.
|
||||
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()
|
||||
{
|
||||
let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?;
|
||||
let (dyn_ty, _dyn_trait) = self.get_ptr_vtable(vptr)?;
|
||||
let recv = self.unpack_dyn_star(&receiver_place, data)?;
|
||||
|
||||
(vptr, dyn_ty, recv.ptr())
|
||||
(data.principal(), recv.layout.ty, recv.ptr())
|
||||
} else {
|
||||
// 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`.)
|
||||
let receiver_tail = self
|
||||
.tcx
|
||||
.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!(
|
||||
self.cur_span(),
|
||||
"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.
|
||||
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
|
||||
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
|
||||
if dyn_trait != data.principal() {
|
||||
throw_ub!(InvalidVTableTrait {
|
||||
expected_trait: data,
|
||||
vtable_trait: dyn_trait,
|
||||
});
|
||||
}
|
||||
let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// compare them to ensure everything fits.
|
||||
let Some(ty::VtblEntry::Method(fn_inst)) =
|
||||
self.get_vtable_entries(vptr)?.get(idx).copied()
|
||||
else {
|
||||
let vtable_entries = if let Some(dyn_trait) = dyn_trait {
|
||||
let trait_ref = dyn_trait.with_self_ty(*self.tcx, dyn_ty);
|
||||
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
|
||||
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);
|
||||
args[0] = FnArg::Copy(
|
||||
ImmTy::from_immediate(
|
||||
Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
|
||||
Scalar::from_maybe_pointer(adjusted_recv, self).into(),
|
||||
self.layout_of(receiver_ty)?,
|
||||
)
|
||||
.into(),
|
||||
@ -974,11 +973,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
let place = match place.layout.ty.kind() {
|
||||
ty::Dynamic(data, _, ty::Dyn) => {
|
||||
// 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) => {
|
||||
// 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!(
|
||||
|
@ -1,11 +1,14 @@
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::interpret::{InterpResult, Pointer};
|
||||
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_trait_selection::traits::ObligationCtxt;
|
||||
use tracing::trace;
|
||||
|
||||
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> {
|
||||
/// 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())
|
||||
}
|
||||
|
||||
/// 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(
|
||||
&self,
|
||||
vtable: Pointer<Option<M::Provenance>>,
|
||||
expected_trait: Option<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>,
|
||||
) -> 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)?;
|
||||
assert!(layout.is_sized(), "there are no vtables for unsized types");
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -343,20 +343,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
||||
match tail.kind() {
|
||||
ty::Dynamic(data, _, ty::Dyn) => {
|
||||
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
|
||||
// Make sure it is a genuine vtable pointer.
|
||||
let (_dyn_ty, dyn_trait) = try_validation!(
|
||||
self.ecx.get_ptr_vtable(vtable),
|
||||
// Make sure it is a genuine vtable pointer for the right trait.
|
||||
try_validation!(
|
||||
self.ecx.get_ptr_vtable_ty(vtable, Some(data)),
|
||||
self.path,
|
||||
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 => {
|
||||
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;
|
||||
|
@ -95,7 +95,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
|
||||
// unsized values are never immediate, so we can assert_mem_place
|
||||
let op = v.to_op(self.ecx())?;
|
||||
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);
|
||||
// recurse with the inner type
|
||||
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
|
||||
// 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).
|
||||
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);
|
||||
}
|
||||
// Slices do not need special handling here: they have `Array` field
|
||||
|
@ -11,6 +11,7 @@ use rustc_session::lint;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
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
|
||||
// stable enough and does not need a feature gate anymore.
|
||||
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;
|
||||
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
|
||||
// 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[¶m_id.to_def_id()];
|
||||
// In the above example this would be .params[..N#0]
|
||||
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
|
||||
// `min_const_generics`.
|
||||
Some(parent_def_id.to_def_id())
|
||||
Some(parent_did)
|
||||
}
|
||||
} else {
|
||||
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), .. })
|
||||
if constant.hir_id() == hir_id =>
|
||||
{
|
||||
Some(parent_def_id.to_def_id())
|
||||
Some(parent_did)
|
||||
}
|
||||
// Exclude `GlobalAsm` here which cannot have generics.
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
@ -171,7 +187,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
_ => false,
|
||||
}) =>
|
||||
{
|
||||
Some(parent_def_id.to_def_id())
|
||||
Some(parent_did)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::flags::FlagComputation;
|
||||
use super::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, TyCtxt, TypeFlags, WithInfcx};
|
||||
use super::{DebruijnIndex, TypeFlags};
|
||||
use crate::arena::Arena;
|
||||
use rustc_data_structures::aligned::{align_of, Aligned};
|
||||
use rustc_serialize::{Encodable, Encoder};
|
||||
@ -162,14 +162,6 @@ impl<H, T: fmt::Debug> fmt::Debug for RawList<H, T> {
|
||||
(**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> {
|
||||
#[inline]
|
||||
|
@ -61,7 +61,6 @@ use rustc_span::{ExpnId, ExpnKind, Span};
|
||||
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
|
||||
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
||||
pub use rustc_type_ir::relate::VarianceDiagInfo;
|
||||
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
|
||||
use tracing::{debug, instrument};
|
||||
pub use vtable::*;
|
||||
|
||||
|
@ -13,7 +13,7 @@ use rustc_ast_ir::visit::VisitorResult;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::abi::TyAndLayout;
|
||||
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx};
|
||||
use rustc_type_ir::ConstKind;
|
||||
|
||||
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> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
WithInfcx::with_no_infcx(self).fmt(f)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
match self.kind {
|
||||
ty::ExprKind::Binop(op) => {
|
||||
let (lhs_ty, rhs_ty, lhs, rhs) = this.data.binop_args();
|
||||
write!(
|
||||
f,
|
||||
"({op:?}: ({:?}: {:?}), ({:?}: {:?}))",
|
||||
&this.wrap(lhs),
|
||||
&this.wrap(lhs_ty),
|
||||
&this.wrap(rhs),
|
||||
&this.wrap(rhs_ty),
|
||||
)
|
||||
let (lhs_ty, rhs_ty, lhs, rhs) = self.binop_args();
|
||||
write!(f, "({op:?}: ({:?}: {:?}), ({:?}: {:?}))", lhs, lhs_ty, rhs, rhs_ty,)
|
||||
}
|
||||
ty::ExprKind::UnOp(op) => {
|
||||
let (rhs_ty, rhs) = this.data.unop_args();
|
||||
write!(f, "({op:?}: ({:?}: {:?}))", &this.wrap(rhs), &this.wrap(rhs_ty))
|
||||
let (rhs_ty, rhs) = self.unop_args();
|
||||
write!(f, "({op:?}: ({:?}: {:?}))", rhs, rhs_ty)
|
||||
}
|
||||
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<_>>();
|
||||
write!(f, "({:?}: {:?})(", &this.wrap(func), &this.wrap(func_ty))?;
|
||||
write!(f, "({:?}: {:?})(", func, func_ty)?;
|
||||
for arg in args.iter().rev().skip(1).rev() {
|
||||
write!(f, "{:?}, ", &this.wrap(arg))?;
|
||||
write!(f, "{:?}, ", arg)?;
|
||||
}
|
||||
if let Some(arg) = args.last() {
|
||||
write!(f, "{:?}", &this.wrap(arg))?;
|
||||
write!(f, "{:?}", arg)?;
|
||||
}
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
ty::ExprKind::Cast(kind) => {
|
||||
let (value_ty, value, to_ty) = this.data.cast_args();
|
||||
write!(
|
||||
f,
|
||||
"({kind:?}: ({:?}: {:?}), {:?})",
|
||||
&this.wrap(value),
|
||||
&this.wrap(value_ty),
|
||||
&this.wrap(to_ty)
|
||||
)
|
||||
let (value_ty, value, to_ty) = self.cast_args();
|
||||
write!(f, "({kind:?}: ({:?}: {:?}), {:?})", value, value_ty, to_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,20 +147,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
||||
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 let ConstKind::Value(_, _) = this.data.kind() {
|
||||
if let ConstKind::Value(_, _) = self.kind() {
|
||||
return ty::tls::with(move |tcx| {
|
||||
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
|
||||
// entire constant.
|
||||
let lifted = tcx.lift(*this.data).unwrap();
|
||||
let lifted = tcx.lift(*self).unwrap();
|
||||
let ConstKind::Value(ty, valtree) = lifted.kind() else {
|
||||
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.
|
||||
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> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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
|
||||
|
@ -1,6 +1,5 @@
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir;
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
|
||||
use crate::coverage::mappings;
|
||||
@ -23,7 +22,7 @@ pub(super) fn extract_refined_covspans(
|
||||
let sorted_span_buckets =
|
||||
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
|
||||
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 }| {
|
||||
// Each span produced by the refiner represents an ordinary code region.
|
||||
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)]
|
||||
struct RefinedCovspan {
|
||||
span: Span,
|
||||
@ -100,164 +47,50 @@ impl RefinedCovspan {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the initial set of coverage spans (one per MIR `Statement` or `Terminator`) into a
|
||||
/// minimal set of coverage spans, using the BCB CFG to determine where it is safe and useful to:
|
||||
///
|
||||
/// * Remove duplicate source code coverage regions
|
||||
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
|
||||
/// execution
|
||||
struct SpansRefiner {
|
||||
/// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
|
||||
/// dominance between the `BasicCoverageBlock`s of equal `Span`s.
|
||||
sorted_spans_iter: std::vec::IntoIter<SpanFromMir>,
|
||||
/// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines"
|
||||
/// those spans by removing spans that overlap in unwanted ways, and by merging
|
||||
/// compatible adjacent spans.
|
||||
#[instrument(level = "debug")]
|
||||
fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
|
||||
// Holds spans that have been read from the input vector, but haven't yet
|
||||
// been committed to the output vector.
|
||||
let mut pending = vec![];
|
||||
let mut refined = vec![];
|
||||
|
||||
/// The current coverage span to compare to its `prev`, to possibly merge, discard,
|
||||
/// or cause `prev` to be modified or discarded.
|
||||
/// If `curr` is not discarded or merged, it becomes `prev` for the next iteration.
|
||||
some_curr: Option<CurrCovspan>,
|
||||
|
||||
/// The coverage span from a prior iteration; typically assigned from that iteration's `curr`.
|
||||
/// 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 {
|
||||
for curr in sorted_spans {
|
||||
pending.retain(|prev: &SpanFromMir| {
|
||||
if prev.span.hi() <= curr.span.lo() {
|
||||
// There's no overlap between the previous/current covspans,
|
||||
// so move the previous one into the refined list.
|
||||
refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
|
||||
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
|
||||
}
|
||||
});
|
||||
|
||||
self.refined_spans
|
||||
pending.push(curr);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn curr(&self) -> &CurrCovspan {
|
||||
self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)"))
|
||||
// Drain the rest of the pending list into the refined list.
|
||||
for prev in pending {
|
||||
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
|
||||
/// `curr` coverage span.
|
||||
#[track_caller]
|
||||
fn take_curr(&mut self) -> CurrCovspan {
|
||||
self.some_curr.take().unwrap_or_else(|| bug!("some_curr is None (take_curr)"))
|
||||
}
|
||||
|
||||
#[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");
|
||||
// Do one last merge pass, to simplify the output.
|
||||
debug!(?refined, "before merge");
|
||||
refined.dedup_by(|b, a| {
|
||||
if a.is_mergeable(b) {
|
||||
debug!(?a, ?b, "merging list-adjacent refined spans");
|
||||
a.merge_from(b);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
debug!(?refined, "after merge");
|
||||
|
||||
/// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
|
||||
/// 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");
|
||||
}
|
||||
}
|
||||
refined
|
||||
}
|
||||
|
@ -8,12 +8,11 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||
use rustc_serialize::Decodable;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::debug::{DebugWithInfcx, WithInfcx};
|
||||
use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use crate::inherent::*;
|
||||
use crate::lift::Lift;
|
||||
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
|
||||
/// 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 {
|
||||
($($t:ty),+ $(,)?) => {
|
||||
$(
|
||||
|
@ -5,7 +5,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use std::fmt;
|
||||
|
||||
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||
use crate::{self as ty, DebruijnIndex, Interner};
|
||||
|
||||
use self::ConstKind::*;
|
||||
|
||||
@ -61,28 +61,19 @@ impl<I: Interner> PartialEq for ConstKind<I> {
|
||||
|
||||
impl<I: Interner> fmt::Debug for ConstKind<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 ConstKind<I> {
|
||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||
this: WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut core::fmt::Formatter<'_>,
|
||||
) -> core::fmt::Result {
|
||||
use ConstKind::*;
|
||||
|
||||
match this.data {
|
||||
match self {
|
||||
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),
|
||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||
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}}"),
|
||||
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> {
|
||||
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")
|
||||
.field("def", &this.data.def)
|
||||
.field("args", &this.wrap(this.data.args))
|
||||
.field("def", &self.def)
|
||||
.field("args", &self.args)
|
||||
.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")]
|
||||
impl<CTX> HashStable<CTX> for InferConst {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -12,11 +12,11 @@ use rustc_ast_ir::Mutability;
|
||||
use crate::fold::{TypeFoldable, TypeSuperFoldable};
|
||||
use crate::relate::Relate;
|
||||
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>>:
|
||||
Copy
|
||||
+ DebugWithInfcx<I>
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ 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>>:
|
||||
Copy
|
||||
+ DebugWithInfcx<I>
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Into<I::GenericArg>
|
||||
@ -134,7 +134,7 @@ pub trait Region<I: Interner<Region = Self>>:
|
||||
|
||||
pub trait Const<I: Interner<Const = Self>>:
|
||||
Copy
|
||||
+ DebugWithInfcx<I>
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Into<I::GenericArg>
|
||||
@ -166,7 +166,7 @@ pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
|
||||
|
||||
pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
||||
Copy
|
||||
+ DebugWithInfcx<I>
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoIterator<Item = I::GenericArg>
|
||||
|
@ -9,7 +9,7 @@ use crate::ir_print::IrPrint;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::inspect::CanonicalGoalEvaluationStep;
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, DebugWithInfcx};
|
||||
use crate::{self as ty};
|
||||
|
||||
pub trait Interner:
|
||||
Sized
|
||||
@ -32,7 +32,7 @@ pub trait Interner:
|
||||
type GenericArgs: GenericArgs<Self>;
|
||||
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
|
||||
type GenericArg: Copy
|
||||
+ DebugWithInfcx<Self>
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = ty::GenericArgKind<Self>>
|
||||
@ -74,9 +74,9 @@ pub trait Interner:
|
||||
|
||||
// Things stored inside of tys
|
||||
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 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 Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>;
|
||||
|
||||
@ -86,7 +86,7 @@ pub trait Interner:
|
||||
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
|
||||
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
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
|
||||
type Region: Region<Self>;
|
||||
|
@ -42,7 +42,6 @@ mod macros;
|
||||
mod binder;
|
||||
mod canonical;
|
||||
mod const_kind;
|
||||
mod debug;
|
||||
mod flags;
|
||||
mod generic_arg;
|
||||
mod infcx;
|
||||
@ -59,7 +58,6 @@ pub use canonical::*;
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use codec::*;
|
||||
pub use const_kind::*;
|
||||
pub use debug::{DebugWithInfcx, WithInfcx};
|
||||
pub use flags::*;
|
||||
pub use generic_arg::*;
|
||||
pub use infcx::InferCtxtLike;
|
||||
|
@ -9,7 +9,7 @@ use crate::inherent::*;
|
||||
use crate::lift::Lift;
|
||||
use crate::upcast::Upcast;
|
||||
use crate::visit::TypeVisitableExt as _;
|
||||
use crate::{self as ty, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
/// `A: 'region`
|
||||
#[derive(derivative::Derivative)]
|
||||
@ -248,16 +248,6 @@ pub enum ExistentialPredicate<I: Interner> {
|
||||
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>> {
|
||||
/// 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`
|
||||
@ -459,7 +449,8 @@ impl AliasTermKind {
|
||||
Copy(bound = ""),
|
||||
Hash(bound = ""),
|
||||
PartialEq(bound = ""),
|
||||
Eq(bound = "")
|
||||
Eq(bound = ""),
|
||||
Debug(bound = "")
|
||||
)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||
@ -493,23 +484,6 @@ pub struct AliasTerm<I: Interner> {
|
||||
_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> {
|
||||
pub fn new(
|
||||
interner: I,
|
||||
|
@ -4,7 +4,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||
use std::fmt;
|
||||
|
||||
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||
use crate::{DebruijnIndex, Interner};
|
||||
|
||||
use self::RegionKind::*;
|
||||
|
||||
@ -18,18 +18,6 @@ rustc_index::newtype_index! {
|
||||
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. For this reason, it internally replaces all the
|
||||
/// 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> {
|
||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||
this: WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut core::fmt::Formatter<'_>,
|
||||
) -> core::fmt::Result {
|
||||
match this.data {
|
||||
impl<I: Interner> fmt::Debug for RegionKind<I> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ReEarlyParam(data) => write!(f, "{data:?}"),
|
||||
|
||||
ReBound(binder_id, bound_region) => {
|
||||
@ -247,7 +232,7 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
|
||||
|
||||
ReStatic => f.write_str("'static"),
|
||||
|
||||
ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)),
|
||||
ReVar(vid) => write!(f, "{:?}", &vid),
|
||||
|
||||
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")]
|
||||
// This is not a derived impl because a derive would require `I: HashStable`
|
||||
|
@ -10,7 +10,7 @@ use std::fmt;
|
||||
pub use self::closure::*;
|
||||
use self::TyKind::*;
|
||||
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;
|
||||
|
||||
@ -341,12 +341,10 @@ impl<I: Interner> PartialEq for TyKind<I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||
this: WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
match this.data {
|
||||
// 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 {
|
||||
match self {
|
||||
Bool => write!(f, "bool"),
|
||||
Char => write!(f, "char"),
|
||||
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(),
|
||||
Str => write!(f, "str"),
|
||||
Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
|
||||
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)),
|
||||
Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
|
||||
RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), this.wrap(ty)),
|
||||
Ref(r, t, m) => write!(f, "&{:?} {}{:?}", this.wrap(r), m.prefix_str(), this.wrap(t)),
|
||||
FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&this.wrap(s)).finish(),
|
||||
FnPtr(s) => write!(f, "{:?}", &this.wrap(s)),
|
||||
Array(t, c) => write!(f, "[{:?}; {:?}]", &t, &c),
|
||||
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &t, &p),
|
||||
Slice(t) => write!(f, "[{:?}]", &t),
|
||||
RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), ty),
|
||||
Ref(r, t, m) => write!(f, "&{:?} {}{:?}", r, m.prefix_str(), t),
|
||||
FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&s).finish(),
|
||||
FnPtr(s) => write!(f, "{:?}", &s),
|
||||
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 => {
|
||||
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(),
|
||||
CoroutineClosure(d, s) => {
|
||||
f.debug_tuple("CoroutineClosure").field(d).field(&this.wrap(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()
|
||||
}
|
||||
Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(),
|
||||
CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&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(),
|
||||
Never => write!(f, "!"),
|
||||
Tuple(t) => {
|
||||
write!(f, "(")?;
|
||||
@ -398,7 +392,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
||||
if count > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{:?}", &this.wrap(ty))?;
|
||||
write!(f, "{:?}", &ty)?;
|
||||
count += 1;
|
||||
}
|
||||
// unary tuples need a trailing comma
|
||||
@ -407,23 +401,16 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
||||
}
|
||||
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:?}"),
|
||||
Bound(d, b) => crate::debug_bound_var(f, *d, b),
|
||||
Placeholder(p) => write!(f, "{p:?}"),
|
||||
Infer(t) => write!(f, "{:?}", this.wrap(t)),
|
||||
Infer(t) => write!(f, "{:?}", t),
|
||||
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.
|
||||
///
|
||||
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
||||
@ -435,7 +422,8 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||
Copy(bound = ""),
|
||||
Hash(bound = ""),
|
||||
PartialEq(bound = ""),
|
||||
Eq(bound = "")
|
||||
Eq(bound = ""),
|
||||
Debug(bound = "")
|
||||
)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||
#[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)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||
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)]
|
||||
#[derivative(
|
||||
Clone(bound = ""),
|
||||
@ -1078,15 +1031,7 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> {
|
||||
|
||||
impl<I: Interner> fmt::Debug for FnSig<I> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
WithInfcx::with_no_infcx(self).fmt(f)
|
||||
}
|
||||
}
|
||||
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 sig = self;
|
||||
let FnSig { inputs_and_output: _, c_variadic, safety, abi } = sig;
|
||||
|
||||
write!(f, "{}", safety.prefix_str())?;
|
||||
@ -1100,7 +1045,7 @@ impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{:?}", &this.wrap(ty))?;
|
||||
write!(f, "{:?}", &ty)?;
|
||||
}
|
||||
if *c_variadic {
|
||||
if inputs.is_empty() {
|
||||
@ -1113,7 +1058,7 @@ impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
|
||||
|
||||
match output.kind() {
|
||||
Tuple(list) if list.is_empty() => Ok(()),
|
||||
_ => write!(f, " -> {:?}", &this.wrap(sig.output())),
|
||||
_ => write!(f, " -> {:?}", sig.output()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -404,9 +404,9 @@ fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option<I::Reifi
|
||||
where
|
||||
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());
|
||||
tagged.0
|
||||
tagged.value.0
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -507,16 +507,9 @@ where
|
||||
///
|
||||
#[unstable(feature = "error_generic_member_access", issue = "99301")]
|
||||
#[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> {
|
||||
/// 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.
|
||||
///
|
||||
/// # Examples
|
||||
@ -940,27 +933,28 @@ pub(crate) mod tags {
|
||||
#[repr(transparent)]
|
||||
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> {
|
||||
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.
|
||||
///
|
||||
/// This trait is exclusively implemented by the `TaggedOption` type.
|
||||
unsafe trait Erased<'a>: 'a {
|
||||
/// The `TypeId` of the erased type.
|
||||
fn tag_id(&self) -> TypeId;
|
||||
unsafe trait Erased<'a>: 'a {}
|
||||
|
||||
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> {
|
||||
fn tag_id(&self) -> TypeId {
|
||||
TypeId::of::<I>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> dyn Erased<'a> + 'a {
|
||||
impl<'a> Tagged<dyn Erased<'a> + 'a> {
|
||||
/// Returns some reference to the dynamic value if it is tagged with `I`,
|
||||
/// or `None` otherwise.
|
||||
#[inline]
|
||||
@ -968,9 +962,9 @@ impl<'a> dyn Erased<'a> + 'a {
|
||||
where
|
||||
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(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
|
||||
Some(&unsafe { &*(self as *const Self).cast::<Tagged<TaggedOption<'a, I>>>() }.value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -983,9 +977,12 @@ impl<'a> dyn Erased<'a> + 'a {
|
||||
where
|
||||
I: tags::Type<'a>,
|
||||
{
|
||||
if self.tag_id() == TypeId::of::<I>() {
|
||||
// SAFETY: Just checked whether we're pointing to an I.
|
||||
Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() })
|
||||
if self.tag_id == TypeId::of::<I>() {
|
||||
Some(
|
||||
// SAFETY: Just checked whether we're pointing to an I.
|
||||
&mut unsafe { &mut *(self as *mut Self).cast::<Tagged<TaggedOption<'a, I>>>() }
|
||||
.value,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -29,9 +29,8 @@ impl<'a> PanicInfo<'a> {
|
||||
PanicInfo { location, message, can_unwind, force_no_backtrace }
|
||||
}
|
||||
|
||||
/// If the `panic!` macro from the `core` crate (not from `std`)
|
||||
/// was used with a formatting string and some additional arguments,
|
||||
/// returns that message ready to be used for example with [`fmt::write`]
|
||||
/// The message that was given to the `panic!` macro,
|
||||
/// ready to be formatted with e.g. [`fmt::write`].
|
||||
#[must_use]
|
||||
#[unstable(feature = "panic_info_message", issue = "66745")]
|
||||
pub fn message(&self) -> fmt::Arguments<'_> {
|
||||
@ -72,7 +71,7 @@ impl<'a> PanicInfo<'a> {
|
||||
|
||||
/// 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`],
|
||||
/// 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::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")]
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
pub fn payload(&self) -> &(dyn crate::any::Any + Send) {
|
||||
|
@ -244,7 +244,11 @@ mod arch {
|
||||
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 {
|
||||
use crate::os::raw::{c_int, c_long};
|
||||
|
||||
|
@ -202,10 +202,7 @@ impl fmt::Display for PanicHookInfo<'_> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("panicked at ")?;
|
||||
self.location.fmt(formatter)?;
|
||||
if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
|
||||
formatter.write_str(":\n")?;
|
||||
formatter.write_str(payload)?;
|
||||
} else if let Some(payload) = self.payload.downcast_ref::<String>() {
|
||||
if let Some(payload) = self.payload_as_str() {
|
||||
formatter.write_str(":\n")?;
|
||||
formatter.write_str(payload)?;
|
||||
}
|
||||
|
@ -428,6 +428,7 @@ auto:
|
||||
RUST_CONFIGURE_ARGS: >-
|
||||
--build=x86_64-pc-windows-msvc
|
||||
--host=aarch64-pc-windows-msvc
|
||||
--target=aarch64-pc-windows-msvc,arm64ec-pc-windows-msvc
|
||||
--enable-full-tools
|
||||
--enable-profiler
|
||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
|
@ -146,6 +146,7 @@ target | std | notes
|
||||
[`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android
|
||||
`arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
|
||||
`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-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)
|
||||
@ -240,7 +241,6 @@ target | std | host | notes
|
||||
-------|:---:|:----:|-------
|
||||
[`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
|
||||
[`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-tvos`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS
|
||||
[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS Simulator
|
||||
|
@ -1,6 +1,6 @@
|
||||
# `arm64ec-pc-windows-msvc`
|
||||
|
||||
**Tier: 3**
|
||||
**Tier: 2**
|
||||
|
||||
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>.
|
||||
@ -21,6 +21,9 @@ Only supported backend is LLVM 18 or above:
|
||||
* 18.1.4 fixed linking issue for some intrinsics implemented in
|
||||
`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?
|
||||
|
||||
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
|
||||
|
||||
Rust does not yet ship pre-compiled artifacts for this target. To compile for
|
||||
this target, you will either need to build Rust with the target enabled (see
|
||||
"Building the target" above), or build your own copy using `build-std` or
|
||||
similar.
|
||||
These targets are distributed through `rustup`, and otherwise require no
|
||||
special configuration.
|
||||
|
||||
## Testing
|
||||
|
||||
|
@ -71,6 +71,7 @@ static TARGETS: &[&str] = &[
|
||||
"arm-unknown-linux-gnueabihf",
|
||||
"arm-unknown-linux-musleabi",
|
||||
"arm-unknown-linux-musleabihf",
|
||||
"arm64ec-pc-windows-msvc",
|
||||
"armv5te-unknown-linux-gnueabi",
|
||||
"armv5te-unknown-linux-musleabi",
|
||||
"armv7-linux-androideabi",
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Validation stops this too early.
|
||||
//@compile-flags: -Zmiri-disable-validation
|
||||
// Validation and SB stop this too early.
|
||||
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
|
||||
|
||||
trait T1 {
|
||||
#[allow(dead_code)]
|
||||
|
@ -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
|
13
tests/coverage/assert-ne.cov-map
Normal file
13
tests/coverage/assert-ne.cov-map
Normal 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)
|
||||
|
23
tests/coverage/assert-ne.coverage
Normal file
23
tests/coverage/assert-ne.coverage
Normal 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.
|
||||
|
22
tests/coverage/assert-ne.rs
Normal file
22
tests/coverage/assert-ne.rs
Normal 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.
|
14
tests/coverage/loop-break.cov-map
Normal file
14
tests/coverage/loop-break.cov-map
Normal 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)
|
||||
|
14
tests/coverage/loop-break.coverage
Normal file
14
tests/coverage/loop-break.coverage
Normal 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!
|
||||
|
13
tests/coverage/loop-break.rs
Normal file
13
tests/coverage/loop-break.rs
Normal 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!
|
@ -5,12 +5,15 @@
|
||||
ty: Coroutine(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[
|
||||
(),
|
||||
std::future::ResumeTy,
|
||||
(),
|
||||
(),
|
||||
CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []),
|
||||
(),
|
||||
(),
|
||||
std::future::ResumeTy,
|
||||
(),
|
||||
(),
|
||||
CoroutineWitness(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[],
|
||||
),
|
||||
(),
|
||||
],
|
||||
),
|
||||
source_info: SourceInfo {
|
||||
@ -23,12 +26,15 @@
|
||||
ty: Coroutine(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[
|
||||
(),
|
||||
std::future::ResumeTy,
|
||||
(),
|
||||
(),
|
||||
CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []),
|
||||
(),
|
||||
(),
|
||||
std::future::ResumeTy,
|
||||
(),
|
||||
(),
|
||||
CoroutineWitness(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[],
|
||||
),
|
||||
(),
|
||||
],
|
||||
),
|
||||
source_info: SourceInfo {
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
+ 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(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(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11;
|
||||
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2;
|
||||
|
22
tests/ui/borrowck/uninitalized-in-match-arm-issue-126133.rs
Normal file
22
tests/ui/borrowck/uninitalized-in-match-arm-issue-126133.rs
Normal 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() {}
|
@ -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`.
|
@ -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) }
|
||||
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) }
|
||||
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), _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), _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), _use_alias_ty_new_instead: () }
|
||||
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
|
||||
--> $DIR/associated-type.rs:31:1
|
||||
|
|
||||
|
@ -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, !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, '^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) }
|
||||
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, !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, '^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) }
|
||||
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), _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), _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), _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), _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), _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), _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), _use_alias_ty_new_instead: () }
|
||||
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)`
|
||||
--> $DIR/associated-type.rs:31:1
|
||||
|
|
||||
|
@ -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() {}
|
@ -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
|
||||
|
@ -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, !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, '^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), _use_alias_ty_new_instead: () }
|
||||
error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
|
||||
--> $DIR/structually-relate-aliases.rs:13:36
|
||||
|
|
||||
|
@ -25,10 +25,10 @@ help: this trait has no implementations, consider adding one
|
||||
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) }
|
||||
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) }
|
||||
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), _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), _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), _use_alias_ty_new_instead: () }
|
||||
error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)`
|
||||
--> $DIR/issue-118950-root-region.rs:19:1
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user