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