mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +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.
|
// for the branching codepaths that aren't covered, to point at them.
|
||||||
let map = self.infcx.tcx.hir();
|
let map = self.infcx.tcx.hir();
|
||||||
let body = map.body_owned_by(self.mir_def_id());
|
let body = map.body_owned_by(self.mir_def_id());
|
||||||
|
let mut visitor =
|
||||||
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
|
ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
|
||||||
visitor.visit_body(&body);
|
visitor.visit_body(&body);
|
||||||
|
|
||||||
let mut show_assign_sugg = false;
|
let mut show_assign_sugg = false;
|
||||||
@ -4372,13 +4372,14 @@ impl<'hir> Visitor<'hir> for BreakFinder {
|
|||||||
|
|
||||||
/// Given a set of spans representing statements initializing the relevant binding, visit all the
|
/// Given a set of spans representing statements initializing the relevant binding, visit all the
|
||||||
/// function expressions looking for branching code paths that *do not* initialize the binding.
|
/// function expressions looking for branching code paths that *do not* initialize the binding.
|
||||||
struct ConditionVisitor<'b> {
|
struct ConditionVisitor<'b, 'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
spans: &'b [Span],
|
spans: &'b [Span],
|
||||||
name: &'b str,
|
name: &'b str,
|
||||||
errors: Vec<(Span, String)>,
|
errors: Vec<(Span, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
||||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||||
match ex.kind {
|
match ex.kind {
|
||||||
hir::ExprKind::If(cond, body, None) => {
|
hir::ExprKind::If(cond, body, None) => {
|
||||||
@ -4464,6 +4465,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
} else if let Some(guard) = &arm.guard {
|
} else if let Some(guard) = &arm.guard {
|
||||||
|
if matches!(
|
||||||
|
self.tcx.hir_node(arm.body.hir_id),
|
||||||
|
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
self.errors.push((
|
self.errors.push((
|
||||||
arm.pat.span.to(guard.span),
|
arm.pat.span.to(guard.span),
|
||||||
format!(
|
format!(
|
||||||
@ -4473,6 +4480,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
if matches!(
|
||||||
|
self.tcx.hir_node(arm.body.hir_id),
|
||||||
|
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
self.errors.push((
|
self.errors.push((
|
||||||
arm.pat.span,
|
arm.pat.span,
|
||||||
format!(
|
format!(
|
||||||
|
@ -387,7 +387,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
|
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
|
||||||
(&ty::Array(_, length), &ty::Slice(_)) => {
|
(&ty::Array(_, length), &ty::Slice(_)) => {
|
||||||
let ptr = self.read_pointer(src)?;
|
let ptr = self.read_pointer(src)?;
|
||||||
// u64 cast is from usize to u64, which is always good
|
|
||||||
let val = Immediate::new_slice(
|
let val = Immediate::new_slice(
|
||||||
ptr,
|
ptr,
|
||||||
length.eval_target_usize(*self.tcx, self.param_env),
|
length.eval_target_usize(*self.tcx, self.param_env),
|
||||||
@ -405,13 +404,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let (old_data, old_vptr) = val.to_scalar_pair();
|
let (old_data, old_vptr) = val.to_scalar_pair();
|
||||||
let old_data = old_data.to_pointer(self)?;
|
let old_data = old_data.to_pointer(self)?;
|
||||||
let old_vptr = old_vptr.to_pointer(self)?;
|
let old_vptr = old_vptr.to_pointer(self)?;
|
||||||
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
|
let ty = self.get_ptr_vtable_ty(old_vptr, Some(data_a))?;
|
||||||
if old_trait != data_a.principal() {
|
|
||||||
throw_ub!(InvalidVTableTrait {
|
|
||||||
expected_trait: data_a,
|
|
||||||
vtable_trait: old_trait,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
|
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
|
||||||
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
||||||
}
|
}
|
||||||
|
@ -765,10 +765,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
}
|
}
|
||||||
Ok(Some((full_size, full_align)))
|
Ok(Some((full_size, full_align)))
|
||||||
}
|
}
|
||||||
ty::Dynamic(_, _, ty::Dyn) => {
|
ty::Dynamic(expected_trait, _, ty::Dyn) => {
|
||||||
let vtable = metadata.unwrap_meta().to_pointer(self)?;
|
let vtable = metadata.unwrap_meta().to_pointer(self)?;
|
||||||
// Read size and align from vtable (already checks size).
|
// Read size and align from vtable (already checks size).
|
||||||
Ok(Some(self.get_vtable_size_and_align(vtable)?))
|
Ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Slice(_) | ty::Str => {
|
ty::Slice(_) | ty::Str => {
|
||||||
|
@ -432,12 +432,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
|
|
||||||
sym::vtable_size => {
|
sym::vtable_size => {
|
||||||
let ptr = self.read_pointer(&args[0])?;
|
let ptr = self.read_pointer(&args[0])?;
|
||||||
let (size, _align) = self.get_vtable_size_and_align(ptr)?;
|
// `None` because we don't know which trait to expect here; any vtable is okay.
|
||||||
|
let (size, _align) = self.get_vtable_size_and_align(ptr, None)?;
|
||||||
self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?;
|
self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?;
|
||||||
}
|
}
|
||||||
sym::vtable_align => {
|
sym::vtable_align => {
|
||||||
let ptr = self.read_pointer(&args[0])?;
|
let ptr = self.read_pointer(&args[0])?;
|
||||||
let (_size, align) = self.get_vtable_size_and_align(ptr)?;
|
// `None` because we don't know which trait to expect here; any vtable is okay.
|
||||||
|
let (_size, align) = self.get_vtable_size_and_align(ptr, None)?;
|
||||||
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
|
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -867,19 +867,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
.ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
|
.ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ptr_vtable(
|
/// Get the dynamic type of the given vtable pointer.
|
||||||
|
/// If `expected_trait` is `Some`, it must be a vtable for the given trait.
|
||||||
|
pub fn get_ptr_vtable_ty(
|
||||||
&self,
|
&self,
|
||||||
ptr: Pointer<Option<M::Provenance>>,
|
ptr: Pointer<Option<M::Provenance>>,
|
||||||
) -> InterpResult<'tcx, (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)> {
|
expected_trait: Option<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>,
|
||||||
|
) -> InterpResult<'tcx, Ty<'tcx>> {
|
||||||
trace!("get_ptr_vtable({:?})", ptr);
|
trace!("get_ptr_vtable({:?})", ptr);
|
||||||
let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
|
let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
|
||||||
if offset.bytes() != 0 {
|
if offset.bytes() != 0 {
|
||||||
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
|
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
|
||||||
}
|
}
|
||||||
match self.tcx.try_get_global_alloc(alloc_id) {
|
let Some(GlobalAlloc::VTable(ty, vtable_trait)) = self.tcx.try_get_global_alloc(alloc_id)
|
||||||
Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)),
|
else {
|
||||||
_ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))),
|
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
|
||||||
|
};
|
||||||
|
if let Some(expected_trait) = expected_trait {
|
||||||
|
self.check_vtable_for_type(vtable_trait, expected_trait)?;
|
||||||
}
|
}
|
||||||
|
Ok(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
|
pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
|
||||||
|
@ -9,7 +9,6 @@ use tracing::{instrument, trace};
|
|||||||
|
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty;
|
|
||||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
@ -1018,54 +1017,6 @@ where
|
|||||||
let layout = self.layout_of(raw.ty)?;
|
let layout = self.layout_of(raw.ty)?;
|
||||||
Ok(self.ptr_to_mplace(ptr.into(), layout))
|
Ok(self.ptr_to_mplace(ptr.into(), layout))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
|
|
||||||
/// Aso returns the vtable.
|
|
||||||
pub(super) fn unpack_dyn_trait(
|
|
||||||
&self,
|
|
||||||
mplace: &MPlaceTy<'tcx, M::Provenance>,
|
|
||||||
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
|
||||||
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)> {
|
|
||||||
assert!(
|
|
||||||
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
|
|
||||||
"`unpack_dyn_trait` only makes sense on `dyn*` types"
|
|
||||||
);
|
|
||||||
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
|
|
||||||
let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
|
|
||||||
if expected_trait.principal() != vtable_trait {
|
|
||||||
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
|
|
||||||
}
|
|
||||||
// This is a kind of transmute, from a place with unsized type and metadata to
|
|
||||||
// a place with sized type and no metadata.
|
|
||||||
let layout = self.layout_of(ty)?;
|
|
||||||
let mplace =
|
|
||||||
MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout };
|
|
||||||
Ok((mplace, vtable))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Turn a `dyn* Trait` type into an value with the actual dynamic type.
|
|
||||||
/// Also returns the vtable.
|
|
||||||
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
|
|
||||||
&self,
|
|
||||||
val: &P,
|
|
||||||
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
|
||||||
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {
|
|
||||||
assert!(
|
|
||||||
matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
|
|
||||||
"`unpack_dyn_star` only makes sense on `dyn*` types"
|
|
||||||
);
|
|
||||||
let data = self.project_field(val, 0)?;
|
|
||||||
let vtable = self.project_field(val, 1)?;
|
|
||||||
let vtable = self.read_pointer(&vtable.to_op(self)?)?;
|
|
||||||
let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
|
|
||||||
if expected_trait.principal() != vtable_trait {
|
|
||||||
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
|
|
||||||
}
|
|
||||||
// `data` is already the right thing but has the wrong type. So we transmute it.
|
|
||||||
let layout = self.layout_of(ty)?;
|
|
||||||
let data = data.transmute(layout, self)?;
|
|
||||||
Ok((data, vtable))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
|
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
@ -827,20 +828,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Obtain the underlying trait we are working on, and the adjusted receiver argument.
|
// Obtain the underlying trait we are working on, and the adjusted receiver argument.
|
||||||
let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) =
|
let (dyn_trait, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) =
|
||||||
receiver_place.layout.ty.kind()
|
receiver_place.layout.ty.kind()
|
||||||
{
|
{
|
||||||
let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?;
|
let recv = self.unpack_dyn_star(&receiver_place, data)?;
|
||||||
let (dyn_ty, _dyn_trait) = self.get_ptr_vtable(vptr)?;
|
|
||||||
|
|
||||||
(vptr, dyn_ty, recv.ptr())
|
(data.principal(), recv.layout.ty, recv.ptr())
|
||||||
} else {
|
} else {
|
||||||
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
|
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
|
||||||
// (For that reason we also cannot use `unpack_dyn_trait`.)
|
// (For that reason we also cannot use `unpack_dyn_trait`.)
|
||||||
let receiver_tail = self
|
let receiver_tail = self
|
||||||
.tcx
|
.tcx
|
||||||
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
|
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
|
||||||
let ty::Dynamic(data, _, ty::Dyn) = receiver_tail.kind() else {
|
let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
self.cur_span(),
|
self.cur_span(),
|
||||||
"dynamic call on non-`dyn` type {}",
|
"dynamic call on non-`dyn` type {}",
|
||||||
@ -851,25 +851,24 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
|
|
||||||
// Get the required information from the vtable.
|
// Get the required information from the vtable.
|
||||||
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
|
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
|
||||||
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
|
let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
|
||||||
if dyn_trait != data.principal() {
|
|
||||||
throw_ub!(InvalidVTableTrait {
|
|
||||||
expected_trait: data,
|
|
||||||
vtable_trait: dyn_trait,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// It might be surprising that we use a pointer as the receiver even if this
|
// It might be surprising that we use a pointer as the receiver even if this
|
||||||
// is a by-val case; this works because by-val passing of an unsized `dyn
|
// is a by-val case; this works because by-val passing of an unsized `dyn
|
||||||
// Trait` to a function is actually desugared to a pointer.
|
// Trait` to a function is actually desugared to a pointer.
|
||||||
(vptr, dyn_ty, receiver_place.ptr())
|
(receiver_trait.principal(), dyn_ty, receiver_place.ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
// Now determine the actual method to call. We can do that in two different ways and
|
// Now determine the actual method to call. We can do that in two different ways and
|
||||||
// compare them to ensure everything fits.
|
// compare them to ensure everything fits.
|
||||||
let Some(ty::VtblEntry::Method(fn_inst)) =
|
let vtable_entries = if let Some(dyn_trait) = dyn_trait {
|
||||||
self.get_vtable_entries(vptr)?.get(idx).copied()
|
let trait_ref = dyn_trait.with_self_ty(*self.tcx, dyn_ty);
|
||||||
else {
|
let trait_ref = self.tcx.erase_regions(trait_ref);
|
||||||
|
self.tcx.vtable_entries(trait_ref)
|
||||||
|
} else {
|
||||||
|
TyCtxt::COMMON_VTABLE_ENTRIES
|
||||||
|
};
|
||||||
|
let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else {
|
||||||
// FIXME(fee1-dead) these could be variants of the UB info enum instead of this
|
// FIXME(fee1-dead) these could be variants of the UB info enum instead of this
|
||||||
throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method);
|
throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method);
|
||||||
};
|
};
|
||||||
@ -898,7 +897,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
|
let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
|
||||||
args[0] = FnArg::Copy(
|
args[0] = FnArg::Copy(
|
||||||
ImmTy::from_immediate(
|
ImmTy::from_immediate(
|
||||||
Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
|
Scalar::from_maybe_pointer(adjusted_recv, self).into(),
|
||||||
self.layout_of(receiver_ty)?,
|
self.layout_of(receiver_ty)?,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
@ -974,11 +973,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let place = match place.layout.ty.kind() {
|
let place = match place.layout.ty.kind() {
|
||||||
ty::Dynamic(data, _, ty::Dyn) => {
|
ty::Dynamic(data, _, ty::Dyn) => {
|
||||||
// Dropping a trait object. Need to find actual drop fn.
|
// Dropping a trait object. Need to find actual drop fn.
|
||||||
self.unpack_dyn_trait(&place, data)?.0
|
self.unpack_dyn_trait(&place, data)?
|
||||||
}
|
}
|
||||||
ty::Dynamic(data, _, ty::DynStar) => {
|
ty::Dynamic(data, _, ty::DynStar) => {
|
||||||
// Dropping a `dyn*`. Need to find actual drop fn.
|
// Dropping a `dyn*`. Need to find actual drop fn.
|
||||||
self.unpack_dyn_star(&place, data)?.0
|
self.unpack_dyn_star(&place, data)?
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::mir::interpret::{InterpResult, Pointer};
|
use rustc_middle::mir::interpret::{InterpResult, Pointer};
|
||||||
use rustc_middle::ty::layout::LayoutOf;
|
use rustc_middle::ty::layout::LayoutOf;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use super::util::ensure_monomorphic_enough;
|
use super::util::ensure_monomorphic_enough;
|
||||||
use super::{InterpCx, Machine};
|
use super::{throw_ub, InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable};
|
||||||
|
|
||||||
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
|
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
|
||||||
@ -33,28 +36,90 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
Ok(vtable_ptr.into())
|
Ok(vtable_ptr.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a high-level representation of the entries of the given vtable.
|
|
||||||
pub fn get_vtable_entries(
|
|
||||||
&self,
|
|
||||||
vtable: Pointer<Option<M::Provenance>>,
|
|
||||||
) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> {
|
|
||||||
let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?;
|
|
||||||
Ok(if let Some(poly_trait_ref) = poly_trait_ref {
|
|
||||||
let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
|
|
||||||
let trait_ref = self.tcx.erase_regions(trait_ref);
|
|
||||||
self.tcx.vtable_entries(trait_ref)
|
|
||||||
} else {
|
|
||||||
TyCtxt::COMMON_VTABLE_ENTRIES
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_vtable_size_and_align(
|
pub fn get_vtable_size_and_align(
|
||||||
&self,
|
&self,
|
||||||
vtable: Pointer<Option<M::Provenance>>,
|
vtable: Pointer<Option<M::Provenance>>,
|
||||||
|
expected_trait: Option<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>,
|
||||||
) -> InterpResult<'tcx, (Size, Align)> {
|
) -> InterpResult<'tcx, (Size, Align)> {
|
||||||
let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?;
|
let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?;
|
||||||
let layout = self.layout_of(ty)?;
|
let layout = self.layout_of(ty)?;
|
||||||
assert!(layout.is_sized(), "there are no vtables for unsized types");
|
assert!(layout.is_sized(), "there are no vtables for unsized types");
|
||||||
Ok((layout.size, layout.align.abi))
|
Ok((layout.size, layout.align.abi))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that the given vtable trait is valid for a pointer/reference/place with the given
|
||||||
|
/// expected trait type.
|
||||||
|
pub(super) fn check_vtable_for_type(
|
||||||
|
&self,
|
||||||
|
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||||
|
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
|
// Fast path: if they are equal, it's all fine.
|
||||||
|
if expected_trait.principal() == vtable_trait {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if let (Some(expected_trait), Some(vtable_trait)) =
|
||||||
|
(expected_trait.principal(), vtable_trait)
|
||||||
|
{
|
||||||
|
// Slow path: spin up an inference context to check if these traits are sufficiently equal.
|
||||||
|
let infcx = self.tcx.infer_ctxt().build();
|
||||||
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
let cause = ObligationCause::dummy_with_span(self.cur_span());
|
||||||
|
// equate the two trait refs after normalization
|
||||||
|
let expected_trait = ocx.normalize(&cause, self.param_env, expected_trait);
|
||||||
|
let vtable_trait = ocx.normalize(&cause, self.param_env, vtable_trait);
|
||||||
|
if ocx.eq(&cause, self.param_env, expected_trait, vtable_trait).is_ok() {
|
||||||
|
if ocx.select_all_or_error().is_empty() {
|
||||||
|
// All good.
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
|
||||||
|
pub(super) fn unpack_dyn_trait(
|
||||||
|
&self,
|
||||||
|
mplace: &MPlaceTy<'tcx, M::Provenance>,
|
||||||
|
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
|
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||||
|
assert!(
|
||||||
|
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
|
||||||
|
"`unpack_dyn_trait` only makes sense on `dyn*` types"
|
||||||
|
);
|
||||||
|
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
|
||||||
|
let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
|
||||||
|
// This is a kind of transmute, from a place with unsized type and metadata to
|
||||||
|
// a place with sized type and no metadata.
|
||||||
|
let layout = self.layout_of(ty)?;
|
||||||
|
let mplace = mplace.offset_with_meta(
|
||||||
|
Size::ZERO,
|
||||||
|
OffsetMode::Wrapping,
|
||||||
|
MemPlaceMeta::None,
|
||||||
|
layout,
|
||||||
|
self,
|
||||||
|
)?;
|
||||||
|
Ok(mplace)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turn a `dyn* Trait` type into an value with the actual dynamic type.
|
||||||
|
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
|
||||||
|
&self,
|
||||||
|
val: &P,
|
||||||
|
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
|
) -> InterpResult<'tcx, P> {
|
||||||
|
assert!(
|
||||||
|
matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
|
||||||
|
"`unpack_dyn_star` only makes sense on `dyn*` types"
|
||||||
|
);
|
||||||
|
let data = self.project_field(val, 0)?;
|
||||||
|
let vtable = self.project_field(val, 1)?;
|
||||||
|
let vtable = self.read_pointer(&vtable.to_op(self)?)?;
|
||||||
|
let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
|
||||||
|
// `data` is already the right thing but has the wrong type. So we transmute it.
|
||||||
|
let layout = self.layout_of(ty)?;
|
||||||
|
let data = data.transmute(layout, self)?;
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,20 +343,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||||||
match tail.kind() {
|
match tail.kind() {
|
||||||
ty::Dynamic(data, _, ty::Dyn) => {
|
ty::Dynamic(data, _, ty::Dyn) => {
|
||||||
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
|
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
|
||||||
// Make sure it is a genuine vtable pointer.
|
// Make sure it is a genuine vtable pointer for the right trait.
|
||||||
let (_dyn_ty, dyn_trait) = try_validation!(
|
try_validation!(
|
||||||
self.ecx.get_ptr_vtable(vtable),
|
self.ecx.get_ptr_vtable_ty(vtable, Some(data)),
|
||||||
self.path,
|
self.path,
|
||||||
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
|
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
|
||||||
InvalidVTablePtr { value: format!("{vtable}") }
|
InvalidVTablePtr { value: format!("{vtable}") },
|
||||||
|
Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
|
||||||
|
InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
|
||||||
|
},
|
||||||
);
|
);
|
||||||
// Make sure it is for the right trait.
|
|
||||||
if dyn_trait != data.principal() {
|
|
||||||
throw_validation_failure!(
|
|
||||||
self.path,
|
|
||||||
InvalidMetaWrongTrait { expected_trait: data, vtable_trait: dyn_trait }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty::Slice(..) | ty::Str => {
|
ty::Slice(..) | ty::Str => {
|
||||||
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;
|
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;
|
||||||
|
@ -95,7 +95,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
|
|||||||
// unsized values are never immediate, so we can assert_mem_place
|
// unsized values are never immediate, so we can assert_mem_place
|
||||||
let op = v.to_op(self.ecx())?;
|
let op = v.to_op(self.ecx())?;
|
||||||
let dest = op.assert_mem_place();
|
let dest = op.assert_mem_place();
|
||||||
let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?.0;
|
let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?;
|
||||||
trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
|
trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
|
||||||
// recurse with the inner type
|
// recurse with the inner type
|
||||||
return self.visit_field(v, 0, &inner_mplace.into());
|
return self.visit_field(v, 0, &inner_mplace.into());
|
||||||
@ -104,7 +104,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
|
|||||||
// DynStar types. Very different from a dyn type (but strangely part of the
|
// DynStar types. Very different from a dyn type (but strangely part of the
|
||||||
// same variant in `TyKind`): These are pairs where the 2nd component is the
|
// same variant in `TyKind`): These are pairs where the 2nd component is the
|
||||||
// vtable, and the first component is the data (which must be ptr-sized).
|
// vtable, and the first component is the data (which must be ptr-sized).
|
||||||
let data = self.ecx().unpack_dyn_star(v, data)?.0;
|
let data = self.ecx().unpack_dyn_star(v, data)?;
|
||||||
return self.visit_field(v, 0, &data);
|
return self.visit_field(v, 0, &data);
|
||||||
}
|
}
|
||||||
// Slices do not need special handling here: they have `Array` field
|
// Slices do not need special handling here: they have `Array` field
|
||||||
|
@ -11,6 +11,7 @@ use rustc_session::lint;
|
|||||||
use rustc_span::symbol::{kw, Symbol};
|
use rustc_span::symbol::{kw, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(tcx))]
|
||||||
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
use rustc_hir::*;
|
use rustc_hir::*;
|
||||||
|
|
||||||
@ -66,7 +67,22 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
// FIXME(#43408) always enable this once `lazy_normalization` is
|
// FIXME(#43408) always enable this once `lazy_normalization` is
|
||||||
// stable enough and does not need a feature gate anymore.
|
// stable enough and does not need a feature gate anymore.
|
||||||
Node::AnonConst(_) => {
|
Node::AnonConst(_) => {
|
||||||
let parent_def_id = tcx.hir().get_parent_item(hir_id);
|
let parent_did = tcx.parent(def_id.to_def_id());
|
||||||
|
|
||||||
|
// We don't do this unconditionally because the `DefId` parent of an anon const
|
||||||
|
// might be an implicitly created closure during `async fn` desugaring. This would
|
||||||
|
// have the wrong generics.
|
||||||
|
//
|
||||||
|
// i.e. `async fn foo<'a>() { let a = [(); { 1 + 2 }]; bar().await() }`
|
||||||
|
// would implicitly have a closure in its body that would be the parent of
|
||||||
|
// the `{ 1 + 2 }` anon const. This closure's generics is simply a witness
|
||||||
|
// instead of `['a]`.
|
||||||
|
let parent_did = if let DefKind::AnonConst = tcx.def_kind(parent_did) {
|
||||||
|
parent_did
|
||||||
|
} else {
|
||||||
|
tcx.hir().get_parent_item(hir_id).to_def_id()
|
||||||
|
};
|
||||||
|
debug!(?parent_did);
|
||||||
|
|
||||||
let mut in_param_ty = false;
|
let mut in_param_ty = false;
|
||||||
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
|
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
|
||||||
@ -121,7 +137,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
//
|
//
|
||||||
// This has some implications for how we get the predicates available to the anon const
|
// This has some implications for how we get the predicates available to the anon const
|
||||||
// see `explicit_predicates_of` for more information on this
|
// see `explicit_predicates_of` for more information on this
|
||||||
let generics = tcx.generics_of(parent_def_id.to_def_id());
|
let generics = tcx.generics_of(parent_did);
|
||||||
let param_def_idx = generics.param_def_id_to_index[¶m_id.to_def_id()];
|
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]
|
// In the above example this would be .params[..N#0]
|
||||||
let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned();
|
let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned();
|
||||||
@ -147,7 +163,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
//
|
//
|
||||||
// Note that we do not supply the parent generics when using
|
// Note that we do not supply the parent generics when using
|
||||||
// `min_const_generics`.
|
// `min_const_generics`.
|
||||||
Some(parent_def_id.to_def_id())
|
Some(parent_did)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let parent_node = tcx.parent_hir_node(hir_id);
|
let parent_node = tcx.parent_hir_node(hir_id);
|
||||||
@ -159,7 +175,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
|
Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
|
||||||
if constant.hir_id() == hir_id =>
|
if constant.hir_id() == hir_id =>
|
||||||
{
|
{
|
||||||
Some(parent_def_id.to_def_id())
|
Some(parent_did)
|
||||||
}
|
}
|
||||||
// Exclude `GlobalAsm` here which cannot have generics.
|
// Exclude `GlobalAsm` here which cannot have generics.
|
||||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||||
@ -171,7 +187,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}) =>
|
}) =>
|
||||||
{
|
{
|
||||||
Some(parent_def_id.to_def_id())
|
Some(parent_did)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::flags::FlagComputation;
|
use super::flags::FlagComputation;
|
||||||
use super::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, TyCtxt, TypeFlags, WithInfcx};
|
use super::{DebruijnIndex, TypeFlags};
|
||||||
use crate::arena::Arena;
|
use crate::arena::Arena;
|
||||||
use rustc_data_structures::aligned::{align_of, Aligned};
|
use rustc_data_structures::aligned::{align_of, Aligned};
|
||||||
use rustc_serialize::{Encodable, Encoder};
|
use rustc_serialize::{Encodable, Encoder};
|
||||||
@ -162,14 +162,6 @@ impl<H, T: fmt::Debug> fmt::Debug for RawList<H, T> {
|
|||||||
(**self).fmt(f)
|
(**self).fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'tcx, H, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for RawList<H, T> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
fmt::Debug::fmt(&this.map(|this| this.as_slice()), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> {
|
impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -61,7 +61,6 @@ use rustc_span::{ExpnId, ExpnKind, Span};
|
|||||||
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
|
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
|
||||||
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
||||||
pub use rustc_type_ir::relate::VarianceDiagInfo;
|
pub use rustc_type_ir::relate::VarianceDiagInfo;
|
||||||
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
|
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
pub use vtable::*;
|
pub use vtable::*;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ use rustc_ast_ir::visit::VisitorResult;
|
|||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_target::abi::TyAndLayout;
|
use rustc_target::abi::TyAndLayout;
|
||||||
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx};
|
use rustc_type_ir::ConstKind;
|
||||||
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
@ -83,14 +83,6 @@ impl fmt::Debug for ty::LateParamRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
this.data.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'tcx> fmt::Debug for Ty<'tcx> {
|
impl<'tcx> fmt::Debug for Ty<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f))
|
with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f))
|
||||||
@ -121,70 +113,33 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
match &**this.data {
|
|
||||||
ty::PatternKind::Range { start, end, include_end } => f
|
|
||||||
.debug_struct("Pattern::Range")
|
|
||||||
.field("start", start)
|
|
||||||
.field("end", end)
|
|
||||||
.field("include_end", include_end)
|
|
||||||
.finish(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
|
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
match self.kind {
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
match this.data.kind {
|
|
||||||
ty::ExprKind::Binop(op) => {
|
ty::ExprKind::Binop(op) => {
|
||||||
let (lhs_ty, rhs_ty, lhs, rhs) = this.data.binop_args();
|
let (lhs_ty, rhs_ty, lhs, rhs) = self.binop_args();
|
||||||
write!(
|
write!(f, "({op:?}: ({:?}: {:?}), ({:?}: {:?}))", lhs, lhs_ty, rhs, rhs_ty,)
|
||||||
f,
|
|
||||||
"({op:?}: ({:?}: {:?}), ({:?}: {:?}))",
|
|
||||||
&this.wrap(lhs),
|
|
||||||
&this.wrap(lhs_ty),
|
|
||||||
&this.wrap(rhs),
|
|
||||||
&this.wrap(rhs_ty),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
ty::ExprKind::UnOp(op) => {
|
ty::ExprKind::UnOp(op) => {
|
||||||
let (rhs_ty, rhs) = this.data.unop_args();
|
let (rhs_ty, rhs) = self.unop_args();
|
||||||
write!(f, "({op:?}: ({:?}: {:?}))", &this.wrap(rhs), &this.wrap(rhs_ty))
|
write!(f, "({op:?}: ({:?}: {:?}))", rhs, rhs_ty)
|
||||||
}
|
}
|
||||||
ty::ExprKind::FunctionCall => {
|
ty::ExprKind::FunctionCall => {
|
||||||
let (func_ty, func, args) = this.data.call_args();
|
let (func_ty, func, args) = self.call_args();
|
||||||
let args = args.collect::<Vec<_>>();
|
let args = args.collect::<Vec<_>>();
|
||||||
write!(f, "({:?}: {:?})(", &this.wrap(func), &this.wrap(func_ty))?;
|
write!(f, "({:?}: {:?})(", func, func_ty)?;
|
||||||
for arg in args.iter().rev().skip(1).rev() {
|
for arg in args.iter().rev().skip(1).rev() {
|
||||||
write!(f, "{:?}, ", &this.wrap(arg))?;
|
write!(f, "{:?}, ", arg)?;
|
||||||
}
|
}
|
||||||
if let Some(arg) = args.last() {
|
if let Some(arg) = args.last() {
|
||||||
write!(f, "{:?}", &this.wrap(arg))?;
|
write!(f, "{:?}", arg)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
ty::ExprKind::Cast(kind) => {
|
ty::ExprKind::Cast(kind) => {
|
||||||
let (value_ty, value, to_ty) = this.data.cast_args();
|
let (value_ty, value, to_ty) = self.cast_args();
|
||||||
write!(
|
write!(f, "({kind:?}: ({:?}: {:?}), {:?})", value, value_ty, to_ty)
|
||||||
f,
|
|
||||||
"({kind:?}: ({:?}: {:?}), {:?})",
|
|
||||||
&this.wrap(value),
|
|
||||||
&this.wrap(value_ty),
|
|
||||||
&this.wrap(to_ty)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,20 +147,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
// If this is a value, we spend some effort to make it look nice.
|
// If this is a value, we spend some effort to make it look nice.
|
||||||
if let ConstKind::Value(_, _) = this.data.kind() {
|
if let ConstKind::Value(_, _) = self.kind() {
|
||||||
return ty::tls::with(move |tcx| {
|
return ty::tls::with(move |tcx| {
|
||||||
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
|
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
|
||||||
// entire constant.
|
// entire constant.
|
||||||
let lifted = tcx.lift(*this.data).unwrap();
|
let lifted = tcx.lift(*self).unwrap();
|
||||||
let ConstKind::Value(ty, valtree) = lifted.kind() else {
|
let ConstKind::Value(ty, valtree) = lifted.kind() else {
|
||||||
bug!("we checked that this is a valtree")
|
bug!("we checked that this is a valtree")
|
||||||
};
|
};
|
||||||
@ -215,7 +162,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Fall back to something verbose.
|
// Fall back to something verbose.
|
||||||
write!(f, "{kind:?}", kind = &this.map(|data| data.kind()))
|
write!(f, "{:?}", self.kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,32 +194,12 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
match this.data.unpack() {
|
|
||||||
GenericArgKind::Lifetime(lt) => write!(f, "{:?}", &this.wrap(lt)),
|
|
||||||
GenericArgKind::Const(ct) => write!(f, "{:?}", &this.wrap(ct)),
|
|
||||||
GenericArgKind::Type(ty) => write!(f, "{:?}", &this.wrap(ty)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for Region<'tcx> {
|
impl<'tcx> fmt::Debug for Region<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{:?}", self.kind())
|
write!(f, "{:?}", self.kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
write!(f, "{:?}", &this.map(|data| data.kind()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Atomic structs
|
// Atomic structs
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use rustc_middle::bug;
|
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
|
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
|
||||||
use crate::coverage::mappings;
|
use crate::coverage::mappings;
|
||||||
@ -23,7 +22,7 @@ pub(super) fn extract_refined_covspans(
|
|||||||
let sorted_span_buckets =
|
let sorted_span_buckets =
|
||||||
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
|
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
|
||||||
for bucket in sorted_span_buckets {
|
for bucket in sorted_span_buckets {
|
||||||
let refined_spans = SpansRefiner::refine_sorted_spans(bucket);
|
let refined_spans = refine_sorted_spans(bucket);
|
||||||
code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| {
|
code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| {
|
||||||
// Each span produced by the refiner represents an ordinary code region.
|
// Each span produced by the refiner represents an ordinary code region.
|
||||||
mappings::CodeMapping { span, bcb }
|
mappings::CodeMapping { span, bcb }
|
||||||
@ -31,58 +30,6 @@ pub(super) fn extract_refined_covspans(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct CurrCovspan {
|
|
||||||
span: Span,
|
|
||||||
bcb: BasicCoverageBlock,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CurrCovspan {
|
|
||||||
fn new(span: Span, bcb: BasicCoverageBlock) -> Self {
|
|
||||||
Self { span, bcb }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_prev(self) -> PrevCovspan {
|
|
||||||
let Self { span, bcb } = self;
|
|
||||||
PrevCovspan { span, bcb, merged_spans: vec![span] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct PrevCovspan {
|
|
||||||
span: Span,
|
|
||||||
bcb: BasicCoverageBlock,
|
|
||||||
/// List of all the original spans from MIR that have been merged into this
|
|
||||||
/// span. Mainly used to precisely skip over gaps when truncating a span.
|
|
||||||
merged_spans: Vec<Span>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrevCovspan {
|
|
||||||
fn is_mergeable(&self, other: &CurrCovspan) -> bool {
|
|
||||||
self.bcb == other.bcb
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_from(&mut self, other: &CurrCovspan) {
|
|
||||||
debug_assert!(self.is_mergeable(other));
|
|
||||||
self.span = self.span.to(other.span);
|
|
||||||
self.merged_spans.push(other.span);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cutoff_statements_at(mut self, cutoff_pos: BytePos) -> Option<RefinedCovspan> {
|
|
||||||
self.merged_spans.retain(|span| span.hi() <= cutoff_pos);
|
|
||||||
if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() {
|
|
||||||
self.span = self.span.with_hi(max_hi);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.merged_spans.is_empty() { None } else { Some(self.into_refined()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_refined(self) -> RefinedCovspan {
|
|
||||||
let Self { span, bcb, merged_spans: _ } = self;
|
|
||||||
RefinedCovspan { span, bcb }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct RefinedCovspan {
|
struct RefinedCovspan {
|
||||||
span: Span,
|
span: Span,
|
||||||
@ -100,164 +47,50 @@ impl RefinedCovspan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the initial set of coverage spans (one per MIR `Statement` or `Terminator`) into a
|
/// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines"
|
||||||
/// minimal set of coverage spans, using the BCB CFG to determine where it is safe and useful to:
|
/// those spans by removing spans that overlap in unwanted ways, and by merging
|
||||||
///
|
/// compatible adjacent spans.
|
||||||
/// * Remove duplicate source code coverage regions
|
#[instrument(level = "debug")]
|
||||||
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
|
fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
|
||||||
/// execution
|
// Holds spans that have been read from the input vector, but haven't yet
|
||||||
struct SpansRefiner {
|
// been committed to the output vector.
|
||||||
/// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
|
let mut pending = vec![];
|
||||||
/// dominance between the `BasicCoverageBlock`s of equal `Span`s.
|
let mut refined = vec![];
|
||||||
sorted_spans_iter: std::vec::IntoIter<SpanFromMir>,
|
|
||||||
|
|
||||||
/// The current coverage span to compare to its `prev`, to possibly merge, discard,
|
for curr in sorted_spans {
|
||||||
/// or cause `prev` to be modified or discarded.
|
pending.retain(|prev: &SpanFromMir| {
|
||||||
/// If `curr` is not discarded or merged, it becomes `prev` for the next iteration.
|
if prev.span.hi() <= curr.span.lo() {
|
||||||
some_curr: Option<CurrCovspan>,
|
// There's no overlap between the previous/current covspans,
|
||||||
|
// so move the previous one into the refined list.
|
||||||
/// The coverage span from a prior iteration; typically assigned from that iteration's `curr`.
|
refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
|
||||||
/// If that `curr` was discarded, `prev` retains its value from the previous iteration.
|
|
||||||
some_prev: Option<PrevCovspan>,
|
|
||||||
|
|
||||||
/// The final coverage spans to add to the coverage map. A `Counter` or `Expression`
|
|
||||||
/// will also be injected into the MIR for each BCB that has associated spans.
|
|
||||||
refined_spans: Vec<RefinedCovspan>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpansRefiner {
|
|
||||||
/// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
|
|
||||||
/// them by merging compatible adjacent spans, removing redundant spans,
|
|
||||||
/// and carving holes in spans when they overlap in unwanted ways.
|
|
||||||
fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
|
|
||||||
let sorted_spans_len = sorted_spans.len();
|
|
||||||
let this = Self {
|
|
||||||
sorted_spans_iter: sorted_spans.into_iter(),
|
|
||||||
some_curr: None,
|
|
||||||
some_prev: None,
|
|
||||||
refined_spans: Vec::with_capacity(sorted_spans_len),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.to_refined_spans()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate through the sorted coverage spans, and return the refined list of merged and
|
|
||||||
/// de-duplicated spans.
|
|
||||||
fn to_refined_spans(mut self) -> Vec<RefinedCovspan> {
|
|
||||||
while self.next_coverage_span() {
|
|
||||||
// For the first span we don't have `prev` set, so most of the
|
|
||||||
// span-processing steps don't make sense yet.
|
|
||||||
if self.some_prev.is_none() {
|
|
||||||
debug!(" initial span");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The remaining cases assume that `prev` and `curr` are set.
|
|
||||||
let prev = self.prev();
|
|
||||||
let curr = self.curr();
|
|
||||||
|
|
||||||
if prev.is_mergeable(curr) {
|
|
||||||
debug!(?prev, "curr will be merged into prev");
|
|
||||||
let curr = self.take_curr();
|
|
||||||
self.prev_mut().merge_from(&curr);
|
|
||||||
} else if prev.span.hi() <= curr.span.lo() {
|
|
||||||
debug!(
|
|
||||||
" different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}",
|
|
||||||
);
|
|
||||||
let prev = self.take_prev().into_refined();
|
|
||||||
self.refined_spans.push(prev);
|
|
||||||
} else {
|
|
||||||
self.cutoff_prev_at_overlapping_curr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is usually a final span remaining in `prev` after the loop ends,
|
|
||||||
// so add it to the output as well.
|
|
||||||
if let Some(prev) = self.some_prev.take() {
|
|
||||||
debug!(" AT END, adding last prev={prev:?}");
|
|
||||||
self.refined_spans.push(prev.into_refined());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do one last merge pass, to simplify the output.
|
|
||||||
self.refined_spans.dedup_by(|b, a| {
|
|
||||||
if a.is_mergeable(b) {
|
|
||||||
debug!(?a, ?b, "merging list-adjacent refined spans");
|
|
||||||
a.merge_from(b);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
// Otherwise, retain the previous covspan only if it has the
|
||||||
|
// same BCB. This tends to discard long outer spans that enclose
|
||||||
|
// smaller inner spans with different control flow.
|
||||||
|
prev.bcb == curr.bcb
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
pending.push(curr);
|
||||||
self.refined_spans
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
// Drain the rest of the pending list into the refined list.
|
||||||
fn curr(&self) -> &CurrCovspan {
|
for prev in pending {
|
||||||
self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)"))
|
refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
|
// Do one last merge pass, to simplify the output.
|
||||||
/// `curr` coverage span.
|
debug!(?refined, "before merge");
|
||||||
#[track_caller]
|
refined.dedup_by(|b, a| {
|
||||||
fn take_curr(&mut self) -> CurrCovspan {
|
if a.is_mergeable(b) {
|
||||||
self.some_curr.take().unwrap_or_else(|| bug!("some_curr is None (take_curr)"))
|
debug!(?a, ?b, "merging list-adjacent refined spans");
|
||||||
}
|
a.merge_from(b);
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn prev(&self) -> &PrevCovspan {
|
|
||||||
self.some_prev.as_ref().unwrap_or_else(|| bug!("some_prev is None (prev)"))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn prev_mut(&mut self) -> &mut PrevCovspan {
|
|
||||||
self.some_prev.as_mut().unwrap_or_else(|| bug!("some_prev is None (prev_mut)"))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn take_prev(&mut self) -> PrevCovspan {
|
|
||||||
self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order.
|
|
||||||
fn next_coverage_span(&mut self) -> bool {
|
|
||||||
if let Some(curr) = self.some_curr.take() {
|
|
||||||
self.some_prev = Some(curr.into_prev());
|
|
||||||
}
|
|
||||||
if let Some(SpanFromMir { span, bcb, .. }) = self.sorted_spans_iter.next() {
|
|
||||||
// This code only sees sorted spans after hole-carving, so there should
|
|
||||||
// be no way for `curr` to start before `prev`.
|
|
||||||
if let Some(prev) = &self.some_prev {
|
|
||||||
debug_assert!(prev.span.lo() <= span.lo());
|
|
||||||
}
|
|
||||||
self.some_curr = Some(CurrCovspan::new(span, bcb));
|
|
||||||
debug!(?self.some_prev, ?self.some_curr, "next_coverage_span");
|
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
debug!(?refined, "after merge");
|
||||||
|
|
||||||
/// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
|
refined
|
||||||
/// statements that end before `curr.lo()` (if any), and add the portion of the
|
|
||||||
/// combined span for those statements. Any other statements have overlapping spans
|
|
||||||
/// that can be ignored because `curr` and/or other upcoming statements/spans inside
|
|
||||||
/// the overlap area will produce their own counters. This disambiguation process
|
|
||||||
/// avoids injecting multiple counters for overlapping spans, and the potential for
|
|
||||||
/// double-counting.
|
|
||||||
fn cutoff_prev_at_overlapping_curr(&mut self) {
|
|
||||||
debug!(
|
|
||||||
" different bcbs, overlapping spans, so ignore/drop pending and only add prev \
|
|
||||||
if it has statements that end before curr; prev={:?}",
|
|
||||||
self.prev()
|
|
||||||
);
|
|
||||||
|
|
||||||
let curr_span = self.curr().span;
|
|
||||||
if let Some(prev) = self.take_prev().cutoff_statements_at(curr_span.lo()) {
|
|
||||||
debug!("after cutoff, adding {prev:?}");
|
|
||||||
self.refined_spans.push(prev);
|
|
||||||
} else {
|
|
||||||
debug!("prev was eliminated by cutoff");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,11 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
|||||||
use rustc_serialize::Decodable;
|
use rustc_serialize::Decodable;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::debug::{DebugWithInfcx, WithInfcx};
|
|
||||||
use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||||
use crate::inherent::*;
|
use crate::inherent::*;
|
||||||
use crate::lift::Lift;
|
use crate::lift::Lift;
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||||
use crate::{self as ty, InferCtxtLike, Interner, SsoHashSet};
|
use crate::{self as ty, Interner, SsoHashSet};
|
||||||
|
|
||||||
/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
|
/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
|
||||||
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
|
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
|
||||||
@ -56,18 +55,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for ty::Binder<I, T> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
f.debug_tuple("Binder")
|
|
||||||
.field(&this.map(|data| data.as_ref().skip_binder()))
|
|
||||||
.field(&this.data.bound_vars())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_binder_encode_decode {
|
macro_rules! impl_binder_encode_decode {
|
||||||
($($t:ty),+ $(,)?) => {
|
($($t:ty),+ $(,)?) => {
|
||||||
$(
|
$(
|
||||||
|
@ -5,7 +5,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
|||||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
use crate::{self as ty, DebruijnIndex, Interner};
|
||||||
|
|
||||||
use self::ConstKind::*;
|
use self::ConstKind::*;
|
||||||
|
|
||||||
@ -61,28 +61,19 @@ impl<I: Interner> PartialEq for ConstKind<I> {
|
|||||||
|
|
||||||
impl<I: Interner> fmt::Debug for ConstKind<I> {
|
impl<I: Interner> fmt::Debug for ConstKind<I> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
use ConstKind::*;
|
use ConstKind::*;
|
||||||
|
|
||||||
match this.data {
|
match self {
|
||||||
Param(param) => write!(f, "{param:?}"),
|
Param(param) => write!(f, "{param:?}"),
|
||||||
Infer(var) => write!(f, "{:?}", &this.wrap(var)),
|
Infer(var) => write!(f, "{:?}", &var),
|
||||||
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
|
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
|
||||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||||
Unevaluated(uv) => {
|
Unevaluated(uv) => {
|
||||||
write!(f, "{:?}", &this.wrap(uv))
|
write!(f, "{:?}", &uv)
|
||||||
}
|
}
|
||||||
Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &this.wrap(ty)),
|
Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &ty),
|
||||||
Error(_) => write!(f, "{{const error}}"),
|
Error(_) => write!(f, "{{const error}}"),
|
||||||
Expr(expr) => write!(f, "{:?}", &this.wrap(expr)),
|
Expr(expr) => write!(f, "{:?}", &expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,17 +103,9 @@ impl<I: Interner> UnevaluatedConst<I> {
|
|||||||
|
|
||||||
impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
|
impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
f.debug_struct("UnevaluatedConst")
|
f.debug_struct("UnevaluatedConst")
|
||||||
.field("def", &this.data.def)
|
.field("def", &self.def)
|
||||||
.field("args", &this.wrap(this.data.args))
|
.field("args", &self.args)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,23 +158,6 @@ impl fmt::Debug for InferConst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<I: Interner> DebugWithInfcx<I> for InferConst {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
match *this.data {
|
|
||||||
InferConst::Var(vid) => match this.infcx.universe_of_ct(vid) {
|
|
||||||
None => write!(f, "{:?}", this.data),
|
|
||||||
Some(universe) => write!(f, "?{}_{}c", vid.index(), universe.index()),
|
|
||||||
},
|
|
||||||
InferConst::EffectVar(vid) => write!(f, "?{}e", vid.index()),
|
|
||||||
InferConst::Fresh(_) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
impl<CTX> HashStable<CTX> for InferConst {
|
impl<CTX> HashStable<CTX> for InferConst {
|
||||||
|
@ -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::fold::{TypeFoldable, TypeSuperFoldable};
|
||||||
use crate::relate::Relate;
|
use crate::relate::Relate;
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom};
|
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
|
||||||
|
|
||||||
pub trait Ty<I: Interner<Ty = Self>>:
|
pub trait Ty<I: Interner<Ty = Self>>:
|
||||||
Copy
|
Copy
|
||||||
+ DebugWithInfcx<I>
|
+ Debug
|
||||||
+ Hash
|
+ Hash
|
||||||
+ Eq
|
+ Eq
|
||||||
+ Into<I::GenericArg>
|
+ Into<I::GenericArg>
|
||||||
@ -116,7 +116,7 @@ pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + TypeVis
|
|||||||
|
|
||||||
pub trait Region<I: Interner<Region = Self>>:
|
pub trait Region<I: Interner<Region = Self>>:
|
||||||
Copy
|
Copy
|
||||||
+ DebugWithInfcx<I>
|
+ Debug
|
||||||
+ Hash
|
+ Hash
|
||||||
+ Eq
|
+ Eq
|
||||||
+ Into<I::GenericArg>
|
+ Into<I::GenericArg>
|
||||||
@ -134,7 +134,7 @@ pub trait Region<I: Interner<Region = Self>>:
|
|||||||
|
|
||||||
pub trait Const<I: Interner<Const = Self>>:
|
pub trait Const<I: Interner<Const = Self>>:
|
||||||
Copy
|
Copy
|
||||||
+ DebugWithInfcx<I>
|
+ Debug
|
||||||
+ Hash
|
+ Hash
|
||||||
+ Eq
|
+ Eq
|
||||||
+ Into<I::GenericArg>
|
+ Into<I::GenericArg>
|
||||||
@ -166,7 +166,7 @@ pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
|
|||||||
|
|
||||||
pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
||||||
Copy
|
Copy
|
||||||
+ DebugWithInfcx<I>
|
+ Debug
|
||||||
+ Hash
|
+ Hash
|
||||||
+ Eq
|
+ Eq
|
||||||
+ IntoIterator<Item = I::GenericArg>
|
+ IntoIterator<Item = I::GenericArg>
|
||||||
|
@ -9,7 +9,7 @@ use crate::ir_print::IrPrint;
|
|||||||
use crate::relate::Relate;
|
use crate::relate::Relate;
|
||||||
use crate::solve::inspect::CanonicalGoalEvaluationStep;
|
use crate::solve::inspect::CanonicalGoalEvaluationStep;
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{self as ty, DebugWithInfcx};
|
use crate::{self as ty};
|
||||||
|
|
||||||
pub trait Interner:
|
pub trait Interner:
|
||||||
Sized
|
Sized
|
||||||
@ -32,7 +32,7 @@ pub trait Interner:
|
|||||||
type GenericArgs: GenericArgs<Self>;
|
type GenericArgs: GenericArgs<Self>;
|
||||||
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
|
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
|
||||||
type GenericArg: Copy
|
type GenericArg: Copy
|
||||||
+ DebugWithInfcx<Self>
|
+ Debug
|
||||||
+ Hash
|
+ Hash
|
||||||
+ Eq
|
+ Eq
|
||||||
+ IntoKind<Kind = ty::GenericArgKind<Self>>
|
+ IntoKind<Kind = ty::GenericArgKind<Self>>
|
||||||
@ -74,9 +74,9 @@ pub trait Interner:
|
|||||||
|
|
||||||
// Things stored inside of tys
|
// Things stored inside of tys
|
||||||
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
|
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
|
||||||
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>;
|
type BoundExistentialPredicates: Copy + Debug + Hash + Eq + Relate<Self>;
|
||||||
type AllocId: Copy + Debug + Hash + Eq;
|
type AllocId: Copy + Debug + Hash + Eq;
|
||||||
type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self> + Relate<Self>;
|
type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
|
||||||
type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>;
|
type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>;
|
||||||
type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>;
|
type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>;
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ pub trait Interner:
|
|||||||
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
|
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
|
||||||
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||||
type ValueConst: Copy + Debug + Hash + Eq;
|
type ValueConst: Copy + Debug + Hash + Eq;
|
||||||
type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>;
|
type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>;
|
||||||
|
|
||||||
// Kinds of regions
|
// Kinds of regions
|
||||||
type Region: Region<Self>;
|
type Region: Region<Self>;
|
||||||
|
@ -42,7 +42,6 @@ mod macros;
|
|||||||
mod binder;
|
mod binder;
|
||||||
mod canonical;
|
mod canonical;
|
||||||
mod const_kind;
|
mod const_kind;
|
||||||
mod debug;
|
|
||||||
mod flags;
|
mod flags;
|
||||||
mod generic_arg;
|
mod generic_arg;
|
||||||
mod infcx;
|
mod infcx;
|
||||||
@ -59,7 +58,6 @@ pub use canonical::*;
|
|||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub use codec::*;
|
pub use codec::*;
|
||||||
pub use const_kind::*;
|
pub use const_kind::*;
|
||||||
pub use debug::{DebugWithInfcx, WithInfcx};
|
|
||||||
pub use flags::*;
|
pub use flags::*;
|
||||||
pub use generic_arg::*;
|
pub use generic_arg::*;
|
||||||
pub use infcx::InferCtxtLike;
|
pub use infcx::InferCtxtLike;
|
||||||
|
@ -9,7 +9,7 @@ use crate::inherent::*;
|
|||||||
use crate::lift::Lift;
|
use crate::lift::Lift;
|
||||||
use crate::upcast::Upcast;
|
use crate::upcast::Upcast;
|
||||||
use crate::visit::TypeVisitableExt as _;
|
use crate::visit::TypeVisitableExt as _;
|
||||||
use crate::{self as ty, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
use crate::{self as ty, Interner};
|
||||||
|
|
||||||
/// `A: 'region`
|
/// `A: 'region`
|
||||||
#[derive(derivative::Derivative)]
|
#[derive(derivative::Derivative)]
|
||||||
@ -248,16 +248,6 @@ pub enum ExistentialPredicate<I: Interner> {
|
|||||||
AutoTrait(I::DefId),
|
AutoTrait(I::DefId),
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Implement this the right way after
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for ExistentialPredicate<I> {
|
|
||||||
fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = I>>(
|
|
||||||
this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
fmt::Debug::fmt(&this.data, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
|
impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
|
||||||
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
||||||
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
|
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
|
||||||
@ -459,7 +449,8 @@ impl AliasTermKind {
|
|||||||
Copy(bound = ""),
|
Copy(bound = ""),
|
||||||
Hash(bound = ""),
|
Hash(bound = ""),
|
||||||
PartialEq(bound = ""),
|
PartialEq(bound = ""),
|
||||||
Eq(bound = "")
|
Eq(bound = ""),
|
||||||
|
Debug(bound = "")
|
||||||
)]
|
)]
|
||||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||||
@ -493,23 +484,6 @@ pub struct AliasTerm<I: Interner> {
|
|||||||
_use_alias_term_new_instead: (),
|
_use_alias_term_new_instead: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> std::fmt::Debug for AliasTerm<I> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for AliasTerm<I> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut std::fmt::Formatter<'_>,
|
|
||||||
) -> std::fmt::Result {
|
|
||||||
f.debug_struct("AliasTerm")
|
|
||||||
.field("args", &this.map(|data| data.args))
|
|
||||||
.field("def_id", &this.data.def_id)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> AliasTerm<I> {
|
impl<I: Interner> AliasTerm<I> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
interner: I,
|
interner: I,
|
||||||
|
@ -4,7 +4,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
|||||||
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
use crate::{DebruijnIndex, Interner};
|
||||||
|
|
||||||
use self::RegionKind::*;
|
use self::RegionKind::*;
|
||||||
|
|
||||||
@ -18,18 +18,6 @@ rustc_index::newtype_index! {
|
|||||||
pub struct RegionVid {}
|
pub struct RegionVid {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for RegionVid {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
match this.infcx.universe_of_lt(*this.data) {
|
|
||||||
Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
|
|
||||||
None => write!(f, "{:?}", this.data),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Representation of regions. Note that the NLL checker uses a distinct
|
/// Representation of regions. Note that the NLL checker uses a distinct
|
||||||
/// representation of regions. For this reason, it internally replaces all the
|
/// representation of regions. For this reason, it internally replaces all the
|
||||||
/// regions with inference variables -- the index of the variable is then used
|
/// regions with inference variables -- the index of the variable is then used
|
||||||
@ -230,12 +218,9 @@ impl<I: Interner> PartialEq for RegionKind<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
|
impl<I: Interner> fmt::Debug for RegionKind<I> {
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
match self {
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
match this.data {
|
|
||||||
ReEarlyParam(data) => write!(f, "{data:?}"),
|
ReEarlyParam(data) => write!(f, "{data:?}"),
|
||||||
|
|
||||||
ReBound(binder_id, bound_region) => {
|
ReBound(binder_id, bound_region) => {
|
||||||
@ -247,7 +232,7 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
|
|||||||
|
|
||||||
ReStatic => f.write_str("'static"),
|
ReStatic => f.write_str("'static"),
|
||||||
|
|
||||||
ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)),
|
ReVar(vid) => write!(f, "{:?}", &vid),
|
||||||
|
|
||||||
RePlaceholder(placeholder) => write!(f, "{placeholder:?}"),
|
RePlaceholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||||
|
|
||||||
@ -260,11 +245,6 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<I: Interner> fmt::Debug for RegionKind<I> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
// This is not a derived impl because a derive would require `I: HashStable`
|
// This is not a derived impl because a derive would require `I: HashStable`
|
||||||
|
@ -10,7 +10,7 @@ use std::fmt;
|
|||||||
pub use self::closure::*;
|
pub use self::closure::*;
|
||||||
use self::TyKind::*;
|
use self::TyKind::*;
|
||||||
use crate::inherent::*;
|
use crate::inherent::*;
|
||||||
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
use crate::{self as ty, DebruijnIndex, Interner};
|
||||||
|
|
||||||
use rustc_ast_ir::Mutability;
|
use rustc_ast_ir::Mutability;
|
||||||
|
|
||||||
@ -341,12 +341,10 @@ impl<I: Interner> PartialEq for TyKind<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
// This is manually implemented because a derive would require `I: Debug`
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f: &mut fmt::Formatter<'_>,
|
match self {
|
||||||
) -> fmt::Result {
|
|
||||||
match this.data {
|
|
||||||
Bool => write!(f, "bool"),
|
Bool => write!(f, "bool"),
|
||||||
Char => write!(f, "char"),
|
Char => write!(f, "char"),
|
||||||
Int(i) => write!(f, "{i:?}"),
|
Int(i) => write!(f, "{i:?}"),
|
||||||
@ -369,27 +367,23 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
|||||||
}
|
}
|
||||||
Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
|
Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
|
||||||
Str => write!(f, "str"),
|
Str => write!(f, "str"),
|
||||||
Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
|
Array(t, c) => write!(f, "[{:?}; {:?}]", &t, &c),
|
||||||
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)),
|
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &t, &p),
|
||||||
Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
|
Slice(t) => write!(f, "[{:?}]", &t),
|
||||||
RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), this.wrap(ty)),
|
RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), ty),
|
||||||
Ref(r, t, m) => write!(f, "&{:?} {}{:?}", this.wrap(r), m.prefix_str(), this.wrap(t)),
|
Ref(r, t, m) => write!(f, "&{:?} {}{:?}", r, m.prefix_str(), t),
|
||||||
FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&this.wrap(s)).finish(),
|
FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&s).finish(),
|
||||||
FnPtr(s) => write!(f, "{:?}", &this.wrap(s)),
|
FnPtr(s) => write!(f, "{:?}", &s),
|
||||||
Dynamic(p, r, repr) => match repr {
|
Dynamic(p, r, repr) => match repr {
|
||||||
DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &this.wrap(p), &this.wrap(r)),
|
DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &p, &r),
|
||||||
DynKind::DynStar => {
|
DynKind::DynStar => {
|
||||||
write!(f, "dyn* {:?} + {:?}", &this.wrap(p), &this.wrap(r))
|
write!(f, "dyn* {:?} + {:?}", &p, &r)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Closure(d, s) => f.debug_tuple("Closure").field(d).field(&this.wrap(s)).finish(),
|
Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(),
|
||||||
CoroutineClosure(d, s) => {
|
CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&s).finish(),
|
||||||
f.debug_tuple("CoroutineClosure").field(d).field(&this.wrap(s)).finish()
|
Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&s).finish(),
|
||||||
}
|
CoroutineWitness(d, s) => f.debug_tuple("CoroutineWitness").field(d).field(&s).finish(),
|
||||||
Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).finish(),
|
|
||||||
CoroutineWitness(d, s) => {
|
|
||||||
f.debug_tuple("CoroutineWitness").field(d).field(&this.wrap(s)).finish()
|
|
||||||
}
|
|
||||||
Never => write!(f, "!"),
|
Never => write!(f, "!"),
|
||||||
Tuple(t) => {
|
Tuple(t) => {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
@ -398,7 +392,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
|||||||
if count > 0 {
|
if count > 0 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{:?}", &this.wrap(ty))?;
|
write!(f, "{:?}", &ty)?;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
// unary tuples need a trailing comma
|
// unary tuples need a trailing comma
|
||||||
@ -407,23 +401,16 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
|||||||
}
|
}
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
Alias(i, a) => f.debug_tuple("Alias").field(i).field(&this.wrap(a)).finish(),
|
Alias(i, a) => f.debug_tuple("Alias").field(i).field(&a).finish(),
|
||||||
Param(p) => write!(f, "{p:?}"),
|
Param(p) => write!(f, "{p:?}"),
|
||||||
Bound(d, b) => crate::debug_bound_var(f, *d, b),
|
Bound(d, b) => crate::debug_bound_var(f, *d, b),
|
||||||
Placeholder(p) => write!(f, "{p:?}"),
|
Placeholder(p) => write!(f, "{p:?}"),
|
||||||
Infer(t) => write!(f, "{:?}", this.wrap(t)),
|
Infer(t) => write!(f, "{:?}", t),
|
||||||
TyKind::Error(_) => write!(f, "{{type error}}"),
|
TyKind::Error(_) => write!(f, "{{type error}}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Debug`
|
|
||||||
impl<I: Interner> fmt::Debug for TyKind<I> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the projection of an associated, opaque, or lazy-type-alias type.
|
/// Represents the projection of an associated, opaque, or lazy-type-alias type.
|
||||||
///
|
///
|
||||||
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
|
||||||
@ -435,7 +422,8 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
|
|||||||
Copy(bound = ""),
|
Copy(bound = ""),
|
||||||
Hash(bound = ""),
|
Hash(bound = ""),
|
||||||
PartialEq(bound = ""),
|
PartialEq(bound = ""),
|
||||||
Eq(bound = "")
|
Eq(bound = ""),
|
||||||
|
Debug(bound = "")
|
||||||
)]
|
)]
|
||||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||||
@ -555,23 +543,6 @@ impl<I: Interner> AliasTy<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> fmt::Debug for AliasTy<I> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
f.debug_struct("AliasTy")
|
|
||||||
.field("args", &this.map(|data| data.args))
|
|
||||||
.field("def_id", &this.data.def_id)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||||
pub enum IntTy {
|
pub enum IntTy {
|
||||||
@ -968,24 +939,6 @@ impl fmt::Debug for InferTy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for InferTy {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
match this.data {
|
|
||||||
InferTy::TyVar(vid) => {
|
|
||||||
if let Some(universe) = this.infcx.universe_of_ty(*vid) {
|
|
||||||
write!(f, "?{}_{}t", vid.index(), universe.index())
|
|
||||||
} else {
|
|
||||||
write!(f, "{:?}", this.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => write!(f, "{:?}", this.data),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(derivative::Derivative)]
|
#[derive(derivative::Derivative)]
|
||||||
#[derivative(
|
#[derivative(
|
||||||
Clone(bound = ""),
|
Clone(bound = ""),
|
||||||
@ -1078,15 +1031,7 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> {
|
|||||||
|
|
||||||
impl<I: Interner> fmt::Debug for FnSig<I> {
|
impl<I: Interner> fmt::Debug for FnSig<I> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
WithInfcx::with_no_infcx(self).fmt(f)
|
let sig = self;
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
|
|
||||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
|
||||||
this: WithInfcx<'_, Infcx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
let sig = this.data;
|
|
||||||
let FnSig { inputs_and_output: _, c_variadic, safety, abi } = sig;
|
let FnSig { inputs_and_output: _, c_variadic, safety, abi } = sig;
|
||||||
|
|
||||||
write!(f, "{}", safety.prefix_str())?;
|
write!(f, "{}", safety.prefix_str())?;
|
||||||
@ -1100,7 +1045,7 @@ impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{:?}", &this.wrap(ty))?;
|
write!(f, "{:?}", &ty)?;
|
||||||
}
|
}
|
||||||
if *c_variadic {
|
if *c_variadic {
|
||||||
if inputs.is_empty() {
|
if inputs.is_empty() {
|
||||||
@ -1113,7 +1058,7 @@ impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
|
|||||||
|
|
||||||
match output.kind() {
|
match output.kind() {
|
||||||
Tuple(list) if list.is_empty() => Ok(()),
|
Tuple(list) if list.is_empty() => Ok(()),
|
||||||
_ => write!(f, " -> {:?}", &this.wrap(sig.output())),
|
_ => write!(f, " -> {:?}", sig.output()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,9 +404,9 @@ fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option<I::Reifi
|
|||||||
where
|
where
|
||||||
I: tags::Type<'a>,
|
I: tags::Type<'a>,
|
||||||
{
|
{
|
||||||
let mut tagged = TaggedOption::<'a, I>(None);
|
let mut tagged = Tagged { tag_id: TypeId::of::<I>(), value: TaggedOption::<'a, I>(None) };
|
||||||
err.provide(tagged.as_request());
|
err.provide(tagged.as_request());
|
||||||
tagged.0
|
tagged.value.0
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -507,16 +507,9 @@ where
|
|||||||
///
|
///
|
||||||
#[unstable(feature = "error_generic_member_access", issue = "99301")]
|
#[unstable(feature = "error_generic_member_access", issue = "99301")]
|
||||||
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
|
||||||
pub struct Request<'a>(dyn Erased<'a> + 'a);
|
pub struct Request<'a>(Tagged<dyn Erased<'a> + 'a>);
|
||||||
|
|
||||||
impl<'a> Request<'a> {
|
impl<'a> Request<'a> {
|
||||||
/// Create a new `&mut Request` from a `&mut dyn Erased` trait object.
|
|
||||||
fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Request<'a> {
|
|
||||||
// SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Request<'a>` is safe since
|
|
||||||
// `Request` is repr(transparent).
|
|
||||||
unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Request<'a>) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provide a value or other type with only static lifetimes.
|
/// Provide a value or other type with only static lifetimes.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -940,27 +933,28 @@ pub(crate) mod tags {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>);
|
pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>);
|
||||||
|
|
||||||
impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> {
|
impl<'a, I: tags::Type<'a>> Tagged<TaggedOption<'a, I>> {
|
||||||
pub(crate) fn as_request(&mut self) -> &mut Request<'a> {
|
pub(crate) fn as_request(&mut self) -> &mut Request<'a> {
|
||||||
Request::new(self as &mut (dyn Erased<'a> + 'a))
|
let erased = self as &mut Tagged<dyn Erased<'a> + 'a>;
|
||||||
|
// SAFETY: transmuting `&mut Tagged<dyn Erased<'a> + 'a>` to `&mut Request<'a>` is safe since
|
||||||
|
// `Request` is repr(transparent).
|
||||||
|
unsafe { &mut *(erased as *mut Tagged<dyn Erased<'a>> as *mut Request<'a>) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a type-erased but identifiable object.
|
/// Represents a type-erased but identifiable object.
|
||||||
///
|
///
|
||||||
/// This trait is exclusively implemented by the `TaggedOption` type.
|
/// This trait is exclusively implemented by the `TaggedOption` type.
|
||||||
unsafe trait Erased<'a>: 'a {
|
unsafe trait Erased<'a>: 'a {}
|
||||||
/// The `TypeId` of the erased type.
|
|
||||||
fn tag_id(&self) -> TypeId;
|
unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {}
|
||||||
|
|
||||||
|
struct Tagged<E: ?Sized> {
|
||||||
|
tag_id: TypeId,
|
||||||
|
value: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {
|
impl<'a> Tagged<dyn Erased<'a> + 'a> {
|
||||||
fn tag_id(&self) -> TypeId {
|
|
||||||
TypeId::of::<I>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> dyn Erased<'a> + 'a {
|
|
||||||
/// Returns some reference to the dynamic value if it is tagged with `I`,
|
/// Returns some reference to the dynamic value if it is tagged with `I`,
|
||||||
/// or `None` otherwise.
|
/// or `None` otherwise.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -968,9 +962,9 @@ impl<'a> dyn Erased<'a> + 'a {
|
|||||||
where
|
where
|
||||||
I: tags::Type<'a>,
|
I: tags::Type<'a>,
|
||||||
{
|
{
|
||||||
if self.tag_id() == TypeId::of::<I>() {
|
if self.tag_id == TypeId::of::<I>() {
|
||||||
// SAFETY: Just checked whether we're pointing to an I.
|
// SAFETY: Just checked whether we're pointing to an I.
|
||||||
Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
|
Some(&unsafe { &*(self as *const Self).cast::<Tagged<TaggedOption<'a, I>>>() }.value)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -983,9 +977,12 @@ impl<'a> dyn Erased<'a> + 'a {
|
|||||||
where
|
where
|
||||||
I: tags::Type<'a>,
|
I: tags::Type<'a>,
|
||||||
{
|
{
|
||||||
if self.tag_id() == TypeId::of::<I>() {
|
if self.tag_id == TypeId::of::<I>() {
|
||||||
// SAFETY: Just checked whether we're pointing to an I.
|
Some(
|
||||||
Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() })
|
// SAFETY: Just checked whether we're pointing to an I.
|
||||||
|
&mut unsafe { &mut *(self as *mut Self).cast::<Tagged<TaggedOption<'a, I>>>() }
|
||||||
|
.value,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,8 @@ impl<'a> PanicInfo<'a> {
|
|||||||
PanicInfo { location, message, can_unwind, force_no_backtrace }
|
PanicInfo { location, message, can_unwind, force_no_backtrace }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the `panic!` macro from the `core` crate (not from `std`)
|
/// The message that was given to the `panic!` macro,
|
||||||
/// was used with a formatting string and some additional arguments,
|
/// ready to be formatted with e.g. [`fmt::write`].
|
||||||
/// returns that message ready to be used for example with [`fmt::write`]
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[unstable(feature = "panic_info_message", issue = "66745")]
|
#[unstable(feature = "panic_info_message", issue = "66745")]
|
||||||
pub fn message(&self) -> fmt::Arguments<'_> {
|
pub fn message(&self) -> fmt::Arguments<'_> {
|
||||||
@ -72,7 +71,7 @@ impl<'a> PanicInfo<'a> {
|
|||||||
|
|
||||||
/// Returns the payload associated with the panic.
|
/// Returns the payload associated with the panic.
|
||||||
///
|
///
|
||||||
/// On `core::panic::PanicInfo`, this method never returns anything useful.
|
/// On this type, `core::panic::PanicInfo`, this method never returns anything useful.
|
||||||
/// It only exists because of compatibility with [`std::panic::PanicHookInfo`],
|
/// It only exists because of compatibility with [`std::panic::PanicHookInfo`],
|
||||||
/// which used to be the same type.
|
/// which used to be the same type.
|
||||||
///
|
///
|
||||||
@ -80,7 +79,7 @@ impl<'a> PanicInfo<'a> {
|
|||||||
///
|
///
|
||||||
/// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html
|
/// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html
|
||||||
/// [`std::panic::PanicHookInfo::payload`]: ../../std/panic/struct.PanicHookInfo.html#method.payload
|
/// [`std::panic::PanicHookInfo::payload`]: ../../std/panic/struct.PanicHookInfo.html#method.payload
|
||||||
#[deprecated(since = "1.77.0", note = "this never returns anything useful")]
|
#[deprecated(since = "1.81.0", note = "this never returns anything useful")]
|
||||||
#[stable(feature = "panic_hooks", since = "1.10.0")]
|
#[stable(feature = "panic_hooks", since = "1.10.0")]
|
||||||
#[allow(deprecated, deprecated_in_future)]
|
#[allow(deprecated, deprecated_in_future)]
|
||||||
pub fn payload(&self) -> &(dyn crate::any::Any + Send) {
|
pub fn payload(&self) -> &(dyn crate::any::Any + Send) {
|
||||||
|
@ -244,7 +244,11 @@ mod arch {
|
|||||||
pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
|
pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(any(
|
||||||
|
target_arch = "aarch64",
|
||||||
|
// Arm64EC is Windows-only, but docs are always build as Linux, so re-use AArch64 for Arm64EC.
|
||||||
|
all(doc, target_arch = "arm64ec")
|
||||||
|
))]
|
||||||
mod arch {
|
mod arch {
|
||||||
use crate::os::raw::{c_int, c_long};
|
use crate::os::raw::{c_int, c_long};
|
||||||
|
|
||||||
|
@ -202,10 +202,7 @@ impl fmt::Display for PanicHookInfo<'_> {
|
|||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
formatter.write_str("panicked at ")?;
|
formatter.write_str("panicked at ")?;
|
||||||
self.location.fmt(formatter)?;
|
self.location.fmt(formatter)?;
|
||||||
if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
|
if let Some(payload) = self.payload_as_str() {
|
||||||
formatter.write_str(":\n")?;
|
|
||||||
formatter.write_str(payload)?;
|
|
||||||
} else if let Some(payload) = self.payload.downcast_ref::<String>() {
|
|
||||||
formatter.write_str(":\n")?;
|
formatter.write_str(":\n")?;
|
||||||
formatter.write_str(payload)?;
|
formatter.write_str(payload)?;
|
||||||
}
|
}
|
||||||
|
@ -428,6 +428,7 @@ auto:
|
|||||||
RUST_CONFIGURE_ARGS: >-
|
RUST_CONFIGURE_ARGS: >-
|
||||||
--build=x86_64-pc-windows-msvc
|
--build=x86_64-pc-windows-msvc
|
||||||
--host=aarch64-pc-windows-msvc
|
--host=aarch64-pc-windows-msvc
|
||||||
|
--target=aarch64-pc-windows-msvc,arm64ec-pc-windows-msvc
|
||||||
--enable-full-tools
|
--enable-full-tools
|
||||||
--enable-profiler
|
--enable-profiler
|
||||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||||
|
@ -146,6 +146,7 @@ target | std | notes
|
|||||||
[`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android
|
[`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android
|
||||||
`arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
|
`arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
|
||||||
`arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat
|
`arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat
|
||||||
|
[`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
|
||||||
[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
|
[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
|
||||||
[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
|
[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
|
||||||
`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
|
`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
|
||||||
@ -240,7 +241,6 @@ target | std | host | notes
|
|||||||
-------|:---:|:----:|-------
|
-------|:---:|:----:|-------
|
||||||
[`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
|
[`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
|
||||||
[`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md) | ✓ | ✓ | ARM64e Apple Darwin
|
[`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md) | ✓ | ✓ | ARM64e Apple Darwin
|
||||||
[`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ? | | Arm64EC Windows MSVC
|
|
||||||
[`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | | Apple Catalyst on ARM64
|
[`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | | Apple Catalyst on ARM64
|
||||||
[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS
|
[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS
|
||||||
[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS Simulator
|
[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ | | ARM64 tvOS Simulator
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# `arm64ec-pc-windows-msvc`
|
# `arm64ec-pc-windows-msvc`
|
||||||
|
|
||||||
**Tier: 3**
|
**Tier: 2**
|
||||||
|
|
||||||
Arm64EC ("Emulation Compatible") for mixed architecture (AArch64 and x86_64)
|
Arm64EC ("Emulation Compatible") for mixed architecture (AArch64 and x86_64)
|
||||||
applications on AArch64 Windows 11. See <https://learn.microsoft.com/en-us/windows/arm/arm64ec>.
|
applications on AArch64 Windows 11. See <https://learn.microsoft.com/en-us/windows/arm/arm64ec>.
|
||||||
@ -21,6 +21,9 @@ Only supported backend is LLVM 18 or above:
|
|||||||
* 18.1.4 fixed linking issue for some intrinsics implemented in
|
* 18.1.4 fixed linking issue for some intrinsics implemented in
|
||||||
`compiler_builtins`.
|
`compiler_builtins`.
|
||||||
|
|
||||||
|
Visual Studio 2022 (or above) with the "ARM64/ARM64EC built tools" component and
|
||||||
|
the Windows 11 SDK are required.
|
||||||
|
|
||||||
### Reusing code from other architectures - x86_64 or AArch64?
|
### Reusing code from other architectures - x86_64 or AArch64?
|
||||||
|
|
||||||
Arm64EC uses `arm64ec` as its `target_arch`, but it is possible to reuse
|
Arm64EC uses `arm64ec` as its `target_arch`, but it is possible to reuse
|
||||||
@ -62,10 +65,8 @@ target = [ "arm64ec-pc-windows-msvc" ]
|
|||||||
|
|
||||||
## Building Rust programs
|
## Building Rust programs
|
||||||
|
|
||||||
Rust does not yet ship pre-compiled artifacts for this target. To compile for
|
These targets are distributed through `rustup`, and otherwise require no
|
||||||
this target, you will either need to build Rust with the target enabled (see
|
special configuration.
|
||||||
"Building the target" above), or build your own copy using `build-std` or
|
|
||||||
similar.
|
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ static TARGETS: &[&str] = &[
|
|||||||
"arm-unknown-linux-gnueabihf",
|
"arm-unknown-linux-gnueabihf",
|
||||||
"arm-unknown-linux-musleabi",
|
"arm-unknown-linux-musleabi",
|
||||||
"arm-unknown-linux-musleabihf",
|
"arm-unknown-linux-musleabihf",
|
||||||
|
"arm64ec-pc-windows-msvc",
|
||||||
"armv5te-unknown-linux-gnueabi",
|
"armv5te-unknown-linux-gnueabi",
|
||||||
"armv5te-unknown-linux-musleabi",
|
"armv5te-unknown-linux-musleabi",
|
||||||
"armv7-linux-androideabi",
|
"armv7-linux-androideabi",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Validation stops this too early.
|
// Validation and SB stop this too early.
|
||||||
//@compile-flags: -Zmiri-disable-validation
|
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
|
||||||
|
|
||||||
trait T1 {
|
trait T1 {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -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(
|
ty: Coroutine(
|
||||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||||
[
|
[
|
||||||
(),
|
(),
|
||||||
std::future::ResumeTy,
|
std::future::ResumeTy,
|
||||||
(),
|
(),
|
||||||
(),
|
(),
|
||||||
CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []),
|
CoroutineWitness(
|
||||||
(),
|
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
source_info: SourceInfo {
|
source_info: SourceInfo {
|
||||||
@ -23,12 +26,15 @@
|
|||||||
ty: Coroutine(
|
ty: Coroutine(
|
||||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||||
[
|
[
|
||||||
(),
|
(),
|
||||||
std::future::ResumeTy,
|
std::future::ResumeTy,
|
||||||
(),
|
(),
|
||||||
(),
|
(),
|
||||||
CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []),
|
CoroutineWitness(
|
||||||
(),
|
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
source_info: SourceInfo {
|
source_info: SourceInfo {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
+ coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) };
|
+ coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) };
|
||||||
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11;
|
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11;
|
||||||
+ coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:11:5 - 12:17;
|
+ coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:12:12 - 12:17;
|
||||||
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18;
|
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18;
|
||||||
+ coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11;
|
+ coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11;
|
||||||
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2;
|
+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2;
|
||||||
|
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), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
|
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
|
||||||
--> $DIR/associated-type.rs:31:1
|
--> $DIR/associated-type.rs:31:1
|
||||||
|
|
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)`
|
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)`
|
||||||
--> $DIR/associated-type.rs:31:1
|
--> $DIR/associated-type.rs:31:1
|
||||||
|
|
|
|
||||||
|
@ -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, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () }
|
||||||
error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
|
error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
|
||||||
--> $DIR/structually-relate-aliases.rs:13:36
|
--> $DIR/structually-relate-aliases.rs:13:36
|
||||||
|
|
|
|
||||||
|
@ -25,10 +25,10 @@ help: this trait has no implementations, consider adding one
|
|||||||
LL | trait ToUnit<'a> {
|
LL | trait ToUnit<'a> {
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
|
||||||
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
|
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () }
|
||||||
error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)`
|
error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)`
|
||||||
--> $DIR/issue-118950-root-region.rs:19:1
|
--> $DIR/issue-118950-root-region.rs:19:1
|
||||||
|
|
|
|
||||||
|
Loading…
Reference in New Issue
Block a user