diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 0984702aa7c39..b5d8fc821ae0e 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -15,11 +15,31 @@ use crate::token::{self, Token}; // Escapes a string, represented as a symbol. Reuses the original symbol, // avoiding interning, if no changes are required. pub fn escape_string_symbol(symbol: Symbol) -> Symbol { - // Don't use escape_default() here, because using it in conjunction with to_string() - // is slow. let s = symbol.as_str(); - let mut escaped = String::with_capacity(s.len()); - for c in s.chars() { + + fn requires_escape(b: &u8) -> bool { + match *b { + b'\\' | b'\'' | b'"' => true, + b'\x20'..=b'\x7e' => false, + _ => true, + } + } + + // Fast-path: if we don't need escaping, just return the original symbol + let Some(position) = s.as_bytes().iter().position(requires_escape) else { + return symbol; + }; + + // At this point we know that we need to escape something in `suffix` + let (prefix, suffix) = s.split_at(position); + + // We set the capacity to the original size + 1, because the resulting string will be at least + // one character larger than the original, because of escaping. + let mut escaped = String::with_capacity(s.len() + 1); + escaped.push_str(prefix); + + // Don't use escape_default() here, because using it is slower than escaping manually. + for c in suffix.chars() { match c { '\t' => escaped.push_str("\\t"), '\r' => escaped.push_str("\\r"), @@ -31,7 +51,7 @@ pub fn escape_string_symbol(symbol: Symbol) -> Symbol { c => write!(escaped, "\\u{{{:x}}}", c as u32).unwrap(), } } - if s == escaped { symbol } else { Symbol::intern(&escaped) } + Symbol::intern(&escaped) } // Escapes a char. diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 96c99e68f95e8..d50e8199c2240 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2497,13 +2497,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // partial initialization, do not complain about mutability // errors except for actual mutation (as opposed to an attempt // to do a partial initialization). - let previously_initialized = self.is_local_ever_initialized(place.local, state); + let previously_initialized = state.ever_inits.contains(place.local); // at this point, we have set up the error reporting state. - if let Some(init_index) = previously_initialized { + if previously_initialized { if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) { // If this is a mutate access to an immutable local variable with no projections // report the error as an illegal reassignment + let init_index = self.first_reaching_init(place.local, location).unwrap(); let init = &self.move_data.inits[init_index]; let assigned_span = init.span(self.body); self.report_illegal_reassignment((place, span), assigned_span, place); @@ -2516,10 +2517,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option { + /// Returns the first init of `local` (in gather order) that may have executed on some path + /// reaching `location` without an intervening `StorageDead(local)`. + fn first_reaching_init(&self, local: Local, location: Location) -> Option { let mpi = self.move_data.rev_lookup.find_local(local)?; - let ii = &self.move_data.init_path_map[mpi]; - ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied() + self.move_data.init_path_map[mpi].iter().copied().find(|&ii| { + let init = self.move_data.inits[ii]; + EverInitializedPlaces::init_reaches_location(self.body, local, init, location) + }) } /// Adds the place into the used mutable variables set @@ -2530,7 +2535,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // mutated, then it is justified to be annotated with the `mut` // keyword, since the mutation may be a possible reassignment. if is_local_mutation_allowed != LocalMutationIsAllowed::Yes - && self.is_local_ever_initialized(local, state).is_some() + && state.ever_inits.contains(local) { self.used_mut.insert(local); } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 80cd892c799cd..bf3cce6e55624 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -315,7 +315,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.storage_live_dyn(local, meta)?; } // Now we can finally actually evaluate the callee place. - let callee_arg = self.eval_place(*callee_arg)?; + let callee_arg = + self.eval_place(*callee_arg, /* skip_validity_for_simple_deref */ false)?; // We allow some transmutes here. // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This // is true for all `copy_op`, but there are a lot of special cases for argument passing @@ -498,7 +499,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // This argument is a VaList holding the remaining caller-side arguments. ecx.storage_live(local)?; - let place = ecx.eval_place(dest)?; + let place = + ecx.eval_place(dest, /* skip_validity_for_simple_deref */ false)?; let mplace = ecx.force_allocation(&place)?; // Consume the remaining arguments by putting them into the variable argument diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 49e9e74191f39..4e42eb4ae158f 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -479,32 +479,34 @@ where trace!("deref to {} on {:?}", val.layout.ty, *val); let mplace = self.imm_ptr_to_mplace(&val)?; - // This is conceptually a typed load from `src` to get the pointer. Most of the time when - // we do typed loads for primitive operations, all relevant invariants are checked - // implicitly, e.g. when we call `to_bool()` on a Boolean. - // But here, we do need to specifically check for metadata validity, null, alignment, and - // dereferenceability, or they will not be checked anywhere at all. - // This duplicates some of the logic in the validity check, but so far we found no - // good way to share that logic. - if ptr_ty.is_ref() || ptr_ty.is_box() { - let kind = if ptr_ty.is_ref() { "reference" } else { "box" }; - - // Null check. - let scalar_ptr = Scalar::from_maybe_pointer(mplace.ptr(), self); - if self.scalar_may_be_null(scalar_ptr)? { - let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar_ptr, Scalar::Ptr(..)); - throw_ub_format!( - "dereferencing a {maybe}null {kind}", - maybe = if maybe { "maybe-" } else { "" } - ); - } + if M::enforce_validity(self, val.layout) { + // This is conceptually a typed load from `src` to get the pointer. Most of the time when + // we do typed loads for primitive operations, all relevant invariants are checked + // implicitly, e.g. when we call `to_bool()` on a Boolean. + // But here, we do need to specifically check for metadata validity, null, alignment, and + // dereferenceability, or they will not be checked anywhere at all. + // This duplicates some of the logic in the validity check, but so far we found no + // good way to share that logic. + if ptr_ty.is_ref() || ptr_ty.is_box() { + let kind = if ptr_ty.is_ref() { "reference" } else { "box" }; + + // Null check. + let scalar_ptr = Scalar::from_maybe_pointer(mplace.ptr(), self); + if self.scalar_may_be_null(scalar_ptr)? { + let maybe = + !M::Provenance::OFFSET_IS_ADDR && matches!(scalar_ptr, Scalar::Ptr(..)); + throw_ub_format!( + "dereferencing a {maybe}null {kind}", + maybe = if maybe { "maybe-" } else { "" } + ); + } - // Dereferencability and alignment check. This also implicitly checks metadata validity. - let (size, align) = self - .size_and_align_of_val(&mplace)? - .unwrap_or_else(|| (mplace.layout.size, mplace.layout.align.abi)); - self.check_ptr_access(mplace.ptr(), size, CheckInAllocMsg::Dereferenceable(kind))?; - self.check_ptr_align(mplace.ptr(), align).map_err_kind(|err| { + // Dereferencability and alignment check. This also implicitly checks metadata validity. + let (size, align) = self + .size_and_align_of_val(&mplace)? + .unwrap_or_else(|| (mplace.layout.size, mplace.layout.align.abi)); + self.check_ptr_access(mplace.ptr(), size, CheckInAllocMsg::Dereferenceable(kind))?; + self.check_ptr_align(mplace.ptr(), align).map_err_kind(|err| { let err_ub!(AlignmentCheckFailed(Misalignment { required, has }, _msg)) = err else { bug!() }; err_ub_format!( "encountered an unaligned {kind} (required {required_bytes} byte alignment but found {found_bytes})", @@ -512,21 +514,22 @@ where found_bytes = has.bytes() ) })?; - } else { - assert!(ptr_ty.is_raw_ptr()); - // For raw pointers, the validity invariant is pretty weak, but we do require the vtable - // to make sense, so we do have to check that if there is one. - if mplace.layout.is_unsized() { - let tail = self.tcx.struct_tail_for_codegen(mplace.layout.ty, self.typing_env); - match tail.kind() { - ty::Dynamic(data, _) => { - let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; - self.get_ptr_vtable_ty(vtable, Some(data))?; - } - ty::Slice(..) | ty::Str | ty::Foreign(..) => { - // Nothing to check (`read_immediate` already ensured initialization). + } else { + assert!(ptr_ty.is_raw_ptr()); + // For raw pointers, the validity invariant is pretty weak, but we do require the vtable + // to make sense, so we do have to check that if there is one. + if mplace.layout.is_unsized() { + let tail = self.tcx.struct_tail_for_codegen(mplace.layout.ty, self.typing_env); + match tail.kind() { + ty::Dynamic(data, _) => { + let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; + self.get_ptr_vtable_ty(vtable, Some(data))?; + } + ty::Slice(..) | ty::Str | ty::Foreign(..) => { + // Nothing to check (`read_immediate` already ensured initialization). + } + _ => bug!("Unexpected unsized type tail: {:?}", tail), } - _ => bug!("Unexpected unsized type tail: {:?}", tail), } } } @@ -590,15 +593,27 @@ where /// Computes a place. You should only use this if you intend to write into this /// place; for reading, a more efficient alternative is `eval_place_to_op`. + /// + /// If `skip_validity_for_simple_deref` is true, then we do not check validity of the inner + /// pointer for places of the form `*ptr`. The caller must justify why that is okay. #[instrument(skip(self), level = "trace")] pub fn eval_place( &self, mir_place: mir::Place<'tcx>, + skip_validity_for_simple_deref: bool, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { let _trace = enter_trace_span!(M, step::eval_place, ?mir_place, tracing_separate_thread = Empty); let mut place = self.local_to_place(mir_place.local)?; + if skip_validity_for_simple_deref + && mir_place.projection.as_slice() == &[mir::ProjectionElem::Deref] + { + // We want to skip the checks in `deref_pointer`. + let val = self.read_immediate(&place)?; + let place = self.imm_ptr_to_mplace(&val)?; + return interp_ok(place.into()); + } // Using `try_fold` turned out to be bad for performance, hence the loop. for elem in mir_place.projection.iter() { place = self.project(&place, elem)? diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index e4b6ff167c1bd..be31393879fff 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -414,7 +414,7 @@ where UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?, Field(field, _) => self.project_field(base, field)?, Downcast(_, variant) => self.project_downcast(base, variant)?, - Deref => self.deref_pointer(&base.to_op(self)?)?.into(), + Deref => self.deref_pointer(base)?.into(), Index(local) => { let layout = self.layout_of(self.tcx.types.usize)?; let n = self.local_to_op(local, Some(layout))?; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 12d4c86a85c94..836f542ee94ff 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -93,7 +93,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Assign((place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?, SetDiscriminant { place, variant_index } => { - let dest = self.eval_place(**place)?; + let dest = + self.eval_place(**place, /* skip_validity_for_simple_deref */ false)?; self.write_discriminant(*variant_index, &dest)?; } @@ -115,7 +116,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Evaluate the place expression, without reading from it. PlaceMention(place) => { - let _ = self.eval_place(**place)?; + let _ = + self.eval_place(**place, /* skip_validity_for_simple_deref */ false)?; } // This exists purely to guide borrowck lifetime inference, and does not have @@ -159,7 +161,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { rvalue: &mir::Rvalue<'tcx>, place: mir::Place<'tcx>, ) -> InterpResult<'tcx> { - let dest = self.eval_place(place)?; + // We can skip validity because we'll write to the place which checks everything we care + // about for references, and the pointee must be sized so there's nothing to check for raw + // pointers. + let dest = self.eval_place(place, /* skip_validity_for_simple_deref */ true)?; // FIXME: ensure some kind of non-aliasing between LHS and RHS? // Also see https://github.com/rust-lang/rust/issues/68364. @@ -206,7 +211,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Ref(_, borrow_kind, place) => { - let src = self.eval_place(place)?; + // `x = &*ptr` does not need a validity check on `ptr` because we will already + // check `x` below. + let src = self.eval_place(place, /* skip_validity_for_simple_deref */ true)?; let place = self.force_allocation(&src)?; let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout); // A fresh reference was created, make sure it gets retagged with the right mode. @@ -251,7 +258,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { false }; - let src = self.eval_place(place)?; + let src = + self.eval_place(place, /* skip_validity_for_simple_deref */ false)?; let place = self.force_allocation(&src)?; let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout); if !place_base_raw && !kind.is_fake() { @@ -403,7 +411,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FnArg::Copy(op) } mir::Operand::Move(place) => { - let place = self.eval_place(*place)?; + // We will read from this place, which checks everything there is to check, + // so we can skip the extra validity check here. + let place = + self.eval_place(*place, /* skip_validity_for_simple_deref */ true)?; if move_definitely_disjoint { // We still have to ensure that no *other* pointers are used to access this place, // so *if* it is in memory then we have to treat it as `InPlace`. @@ -553,7 +564,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let old_loc = self.frame().loc; // Evaluation order consistent with assignment: destination first. - let dest_place = self.eval_place(destination)?; + let dest_place = + self.eval_place(destination, /* skip_validity_for_simple_deref */ false)?; let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } = self.eval_callee_and_args(terminator, func, args, &destination)?; @@ -602,7 +614,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { drop.is_none(), "Async Drop must be expanded or reset to sync in runtime MIR" ); - let place = self.eval_place(place)?; + let place = + self.eval_place(place, /* skip_validity_for_simple_deref */ false)?; let instance = { let _trace = enter_trace_span!(M, resolve::resolve_drop_glue, ty = ?place.layout.ty); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 7cfe32b78b577..160c5b2266c22 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -23,8 +23,9 @@ use rustc_span::{BytePos, DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; +use rustc_trait_selection::solve::NextSolverError; use rustc_trait_selection::traits::{ - self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, + self, FromSolverError, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, }; use tracing::{debug, instrument}; @@ -802,7 +803,8 @@ struct ImplTraitInTraitCollector<'a, 'tcx, E> { impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E> where - E: 'tcx, + E: FromSolverError<'tcx, NextSolverError<'tcx>> + + FromSolverError<'tcx, traits::OldSolverError<'tcx>>, { fn new( ocx: &'a ObligationCtxt<'a, 'tcx, E>, @@ -816,7 +818,8 @@ where impl<'tcx, E> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx, E> where - E: 'tcx, + E: FromSolverError<'tcx, NextSolverError<'tcx>> + + FromSolverError<'tcx, traits::OldSolverError<'tcx>>, { fn cx(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 68b7d50c2ee9b..3402f56bef6dc 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -63,13 +63,26 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let icx = ItemCtxt::new(tcx, def_id); + let new_bound_fn_def = |hir: HirId, did| { + let args = ty::GenericArgs::identity_for_item(tcx, def_id); + Ty::new_fn_def( + tcx, + did, + match &tcx + .late_bound_vars_map(hir.owner) + .get(&hir.local_id) + .cloned() + .map(|x| tcx.mk_bound_variable_kinds(&x)) + { + Some(late_bound) => ty::Binder::bind_with_vars(args, late_bound), + None => ty::Binder::dummy(args), + }, + ) + }; + let output = match tcx.hir_node(hir_id) { Node::TraitItem(item) => match item.kind { - TraitItemKind::Fn(..) => { - let args = ty::GenericArgs::identity_for_item(tcx, def_id); - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ty::new_fn_def(tcx, def_id.to_def_id(), ty::Binder::dummy(args)) - } + TraitItemKind::Fn(_, _) => new_bound_fn_def(item.hir_id(), def_id.to_def_id()), TraitItemKind::Const(ty, rhs) => rhs .and_then(|rhs| { ty.is_suggestable_infer_ty().then(|| { @@ -92,11 +105,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ }, Node::ImplItem(item) => match item.kind { - ImplItemKind::Fn(..) => { - let args = ty::GenericArgs::identity_for_item(tcx, def_id); - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ty::new_fn_def(tcx, def_id.to_def_id(), ty::Binder::dummy(args)) - } + ImplItemKind::Fn(_, _) => new_bound_fn_def(item.hir_id(), def_id.to_def_id()), ImplItemKind::Const(ty, rhs) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( @@ -171,11 +180,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } _ => icx.lower_ty(self_ty), }, - ItemKind::Fn { .. } => { - let args = ty::GenericArgs::identity_for_item(tcx, def_id); - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ty::new_fn_def(tcx, def_id.to_def_id(), ty::Binder::dummy(args)) - } + ItemKind::Fn { .. } => new_bound_fn_def(item.hir_id(), def_id.to_def_id()), ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { let def = tcx.adt_def(def_id); let args = ty::GenericArgs::identity_for_item(tcx, def_id); @@ -196,10 +201,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).instantiate_identity().skip_norm_wip(), Node::ForeignItem(foreign_item) => match foreign_item.kind { - ForeignItemKind::Fn(..) => { - let args = ty::GenericArgs::identity_for_item(tcx, def_id); - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ty::new_fn_def(tcx, def_id.to_def_id(), ty::Binder::dummy(args)) + ForeignItemKind::Fn(_, _, _generics) => { + new_bound_fn_def(foreign_item.hir_id(), def_id.to_def_id()) } ForeignItemKind::Static(ty, _, _) => { let ty = icx.lower_ty(ty); @@ -219,11 +222,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ VariantData::Unit(..) | VariantData::Struct { .. } => { tcx.type_of(tcx.hir_get_parent_item(hir_id)).instantiate_identity().skip_norm_wip() } - VariantData::Tuple(_, _, ctor) => { - let args = ty::GenericArgs::identity_for_item(tcx, def_id); - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ty::new_fn_def(tcx, ctor.to_def_id(), ty::Binder::dummy(args)) - } + VariantData::Tuple(_, hir_id, ctor) => new_bound_fn_def(*hir_id, ctor.to_def_id()), }, Node::Field(field) => icx.lower_ty(field.ty), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index aea2226815ce4..fa3dca042ba0c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1483,13 +1483,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok(ct) } TypeRelativePath::Ctor { ctor_def_id, args } => match tcx.def_kind(ctor_def_id) { - DefKind::Ctor(_, CtorKind::Fn) => { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ok(ty::Const::zero_sized( - tcx, - tcx.type_of(ctor_def_id).instantiate(tcx, args).skip_norm_wip(), - )) - } + DefKind::Ctor(_, CtorKind::Fn) => Ok(ty::Const::zero_sized( + tcx, + tcx.type_of(ctor_def_id).instantiate(tcx, args).skip_norm_wip(), + )), DefKind::Ctor(ctor_of, CtorKind::Const) => { Ok(self.construct_const_ctor_value(ctor_def_id, ctor_of, args)) } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6f9b6a4f14ce9..f89d67eced3fb 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -631,7 +631,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be known if explicitly specified via turbofish). self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } - if tcx.is_intrinsic(did, sym::offload) { + if !tcx.sess.opts.unstable_opts.offload.is_empty() + && tcx.is_intrinsic(did, sym::offload) + { let args = args.skip_binder(); let f = args.type_at(0); let t = args.type_at(1); diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 0e34a6120b609..e753100a5e1a9 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, FloatVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisit use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; -use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt, TraitEngine}; use tracing::debug; use crate::{FnCtxt, diagnostics}; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 1886888c476a0..a7651cf365edd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -37,7 +37,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::traits::{ - self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt, + self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt, TraitEngine, }; use tracing::{debug, instrument}; @@ -1498,7 +1498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in a reentrant borrow, causing an ICE. let result = self.at(&self.misc(sp), self.param_env).structurally_normalize_const( Unnormalized::new_wip(ct), - &mut **self.fulfillment_cx.borrow_mut(), + &mut *self.fulfillment_cx.borrow_mut(), ); match result { Ok(normalized_ct) => normalized_ct, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index bc1dd222c56ca..e6de8b55ef2f9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -2,7 +2,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::DefId; -use rustc_infer::traits::{self, ObligationCause, PredicateObligations}; +use rustc_infer::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::solve::Certainty; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 5c5bf77609ce2..c67b8f7cdaf5c 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -49,7 +49,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, HirIdMap, Node}; use rustc_hir_analysis::check::{check_abi, check_custom_abi}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; +use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, TraitEngine, WellFormedLoc}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::query::Providers; use rustc_middle::ty::{self, FnSigKind, Ty, TyCtxt, Unnormalized}; diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index a475d073f452d..945e14b3d98fa 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -8,7 +8,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt, TyVid, TypeVisitableExt, TypingMode}; use rustc_span::Span; use rustc_span::def_id::LocalDefIdMap; -use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine, TraitEngineExt as _}; +use rustc_trait_selection::traits::{self, FulfillmentEngine, FulfillmentError, TraitEngine}; use tracing::instrument; use super::callee::DeferredCallResolution; @@ -31,7 +31,7 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) locals: RefCell>>, - pub(super) fulfillment_cx: RefCell>>>, + pub(super) fulfillment_cx: RefCell>>, // Used to detect opaque types uses added after we've already checked them. // @@ -87,7 +87,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { .in_hir_typeck() .build(TypingMode::typeck_for_body(tcx, def_id)); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); - let fulfillment_cx = RefCell::new(>::new(&infcx)); + let fulfillment_cx = RefCell::new(FulfillmentEngine::new(&infcx)); TypeckRootCtxt { infcx, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 15bb0d5ddb266..ccf853f02bca5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1154,7 +1154,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if not_typeck_child { tcx.ensure_ok().mir_borrowck(def_id); tcx.ensure_ok().check_transmutes(def_id); - tcx.ensure_ok().check_offloads(def_id); + if !tcx.sess.opts.unstable_opts.offload.is_empty() { + tcx.ensure_ok().check_offloads(def_id); + } } tcx.ensure_ok().has_ffi_unwind_calls(def_id); tcx.ensure_ok().check_liveness(def_id); diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index bb91d855feaeb..8879c175da2f9 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -34,7 +34,7 @@ use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_target::spec::{PanicStrategy, Target}; -use tracing::{debug, info, trace}; +use tracing::{debug, info}; use crate::diagnostics; use crate::locator::{CrateError, CrateLocator, CratePaths, CrateRejections}; @@ -69,6 +69,9 @@ pub struct CStore { /// This crate has a `#[alloc_error_handler]` item. has_alloc_error_handler: bool, + /// Cached map from hash to CrateNum, to avoid scanning metas during crate resolution. + hash_to_cnum: UnordMap, + /// Names that were used to load the crates via `extern crate` or paths. resolved_externs: UnordMap, @@ -237,6 +240,7 @@ impl CStore { fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) { assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry"); + self.hash_to_cnum.insert(data.hash(), cnum); self.metas[cnum] = Some(Box::new(data)); } @@ -546,6 +550,7 @@ impl CStore { alloc_error_handler_kind: None, has_global_allocator: false, has_alloc_error_handler: false, + hash_to_cnum: UnordMap::default(), resolved_externs: UnordMap::default(), unused_externs: Vec::new(), used_extern_options: Default::default(), @@ -555,21 +560,9 @@ impl CStore { fn existing_match(&self, name: Symbol, hash: Option) -> Option { let hash = hash?; - - for (cnum, data) in self.iter_crate_data() { - if data.name() != name { - trace!("{} did not match {}", data.name(), name); - continue; - } - - if hash == data.hash() { - return Some(cnum); - } else { - debug!("actual hash {} did not match expected {}", hash, data.hash()); - } - } - - None + let cnum = *self.hash_to_cnum.get(&hash)?; + debug_assert_eq!(self.get_crate_data(cnum).name(), name); + Some(cnum) } /// Determine whether a dependency should be considered private. diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index f1c432779f217..6ad87ada17ff4 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1135,7 +1135,7 @@ rustc_queries! { desc { "check transmute calls inside `{}`", tcx.def_path_str(key) } } - /// Unsafety-check this `LocalDefId`. + /// Type-check offloads calls given a typeck root query check_offloads(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { "check offload calls inside `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 5bfa74ba20eb4..b7b20bcdb850a 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -144,6 +144,7 @@ impl Node { #[derive(Copy, Clone)] pub struct Ancestors<'tcx> { + tcx: TyCtxt<'tcx>, trait_def_id: DefId, specialization_graph: &'tcx Graph, current_source: Option, @@ -154,7 +155,14 @@ impl Iterator for Ancestors<'_> { fn next(&mut self) -> Option { let cur = self.current_source.take(); if let Some(Node::Impl(cur_impl)) = cur { - let parent = self.specialization_graph.parent(cur_impl); + // Graph construction may skip foreign impls, so resolve a foreign impl's + // parent from crate metadata instead; recorded foreign impls use the same + // value (see `record_impl_from_cstore`). + let parent = if cur_impl.is_local() { + self.specialization_graph.parent(cur_impl) + } else { + self.tcx.impl_parent(cur_impl).unwrap_or(self.trait_def_id) + }; self.current_source = if parent == self.trait_def_id { Some(Node::Trait(parent)) @@ -254,6 +262,7 @@ pub fn ancestors( Err(reported) } else { Ok(Ancestors { + tcx, trait_def_id, specialization_graph, current_source: Some(Node::Impl(start_from_impl)), diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e768c75961937..6c449eb62ae22 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -735,7 +735,6 @@ impl<'tcx> Ty<'tcx> { tcx.def_kind(def_id), DefKind::AssocFn | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) ); - // FIXME(156581): check that the binder is being used correctly (turbofishing/fndef changes) let args = args.map_bound(|args| tcx.check_and_mk_args(def_id, args)); Ty::new(tcx, FnDef(def_id, args)) } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 41882f6344ea6..bdf45e0c85cb5 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -532,7 +532,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success = this.cfg.start_new_block(); let clone_trait = this.tcx.require_lang_item(LangItem::Clone, span); let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) let func = Operand::function_handle(this.tcx, clone_fn, &[ty.into()], expr_span); let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 4ca5ee56315a4..543c833326021 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,16 +1,20 @@ use std::assert_matches; use rustc_abi::VariantIdx; -use rustc_index::Idx; +use rustc_data_structures::fx::FxIndexSet; use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; use rustc_middle::bug; -use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges}; +use rustc_middle::mir::{ + self, BasicBlock, Body, CallReturnPlaces, Local, Location, StatementKind, TerminatorEdges, +}; use rustc_middle::ty::{self, TyCtxt}; use smallvec::SmallVec; -use tracing::{debug, instrument}; +use tracing::instrument; use crate::drop_flag_effects::{DropFlagState, InactiveVariants}; -use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; +use crate::move_paths::{ + HasMoveData, Init, InitKind, InitLocation, LookupResult, MoveData, MovePathIndex, +}; use crate::{ Analysis, GenKill, MaybeReachable, SwitchTargetIndex, drop_flag_effects, drop_flag_effects_for_function_entry, drop_flag_effects_for_location, on_all_children_bits, @@ -267,36 +271,34 @@ impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } -/// `EverInitializedPlaces` tracks all initializations that may have occurred -/// upon reaching a particular point in the control flow for a function, -/// without an intervening `StorageDead`. +/// `EverInitializedPlaces` tracks all initializations of locals that may have +/// occurred upon reaching a particular point in the control flow for a +/// function, without an intervening `StorageDead`. /// /// This dataflow is used to determine if an immutable local variable may /// be assigned to. /// /// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. Underscored indices -/// are used to distinguish between multiple initializations of the same local -/// variable, e.g. `b_0` and `b_1`. +/// dataflow information shown in the right-hand comments. /// /// ```rust /// struct S; /// #[rustfmt::skip] /// fn foo(p: bool) { // ever-init: -/// // {p, } -/// let a = S; let mut b = S; let c; let d; // {p, a, b_0, } +/// // {p, } +/// let a = S; let mut b = S; let c; let d; // {p, a, b, } /// /// if p { -/// drop(a); // {p, a, b_0, } -/// b = S; // {p, a, b_0, b_1, } +/// drop(a); // {p, a, b, } +/// b = S; // {p, a, b, } /// /// } else { -/// drop(b); // {p, a, b_0, b_1, } -/// d = S; // {p, a, b_0, b_1, d} +/// drop(b); // {p, a, b, } +/// d = S; // {p, a, b, d} /// -/// } // {p, a, b_0, b_1, d} +/// } // {p, a, b, d} /// -/// c = S; // {p, a, b_0, b_1, c, d} +/// c = S; // {p, a, b, c, d} /// } /// ``` pub struct EverInitializedPlaces<'a, 'tcx> { @@ -590,23 +592,21 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } -/// There can be many more `InitIndex` than there are locals in a MIR body. -/// We use a mixed bitset to avoid paying too high a memory footprint. -pub type EverInitializedPlacesDomain = MixedBitSet; +pub type EverInitializedPlacesDomain = DenseBitSet; impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { type Domain = EverInitializedPlacesDomain; const NAME: &'static str = "ever_init"; - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = no initialized variables by default - MixedBitSet::new_empty(self.move_data().inits.len()) + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = no initialized locals by default + DenseBitSet::new_empty(body.local_decls.len()) } fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { - for arg_init in 0..body.arg_count { - state.insert(InitIndex::new(arg_init)); + for arg in body.args_iter() { + state.insert(arg); } } @@ -618,20 +618,18 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { location: Location, ) { let move_data = self.move_data(); - let init_path_map = &move_data.init_path_map; let init_loc_map = &move_data.init_loc_map; - let rev_lookup = &move_data.rev_lookup; - debug!("initializes move_indexes {:?}", init_loc_map[location]); - state.gen_all(init_loc_map[location].iter().copied()); + // Record inits of locals. Projections can be ignored. + state.gen_all(init_loc_map[location].iter().copied().filter_map(|ii| { + let init_mpi = move_data.inits[ii].path; + move_data.move_paths[init_mpi].place.as_local() + })); - if let mir::StatementKind::StorageDead(local) = stmt.kind - // End inits for StorageDead, so that an immutable variable can - // be reinitialized on the next iteration of the loop. - && let Some(move_path_index) = rev_lookup.find_local(local) - { - debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]); - state.kill_all(init_path_map[move_path_index].iter().copied()); + // Kill on StorageDead, so that an immutable variable can + // be reinitialized on the next iteration of the loop. + if let mir::StatementKind::StorageDead(local) = stmt.kind { + state.kill(local); } } @@ -644,16 +642,16 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> { let move_data = self.move_data(); let init_loc_map = &move_data.init_loc_map; - debug!(?terminator); - debug!("initializes move_indexes {:?}", init_loc_map[location]); - state.gen_all( - init_loc_map[location] - .iter() - .filter(|init_index| { - move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly - }) - .copied(), - ); + + // Record inits of locals. Projections can be ignored. + state.gen_all(init_loc_map[location].iter().copied().filter_map(|ii| { + let init = &move_data.inits[ii]; + if init.kind != InitKind::NonPanicPathOnly { + move_data.move_paths[init.path].place.as_local() + } else { + None + } + })); terminator.edges() } @@ -666,9 +664,77 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let move_data = self.move_data(); let init_loc_map = &move_data.init_loc_map; + // Record inits of locals. Projections can be ignored. let call_loc = self.body.terminator_loc(block); - for init_index in &init_loc_map[call_loc] { - state.gen_(*init_index); + state.gen_all(init_loc_map[call_loc].iter().copied().filter_map(|ii| { + let init = &move_data.inits[ii]; + if init.kind == InitKind::NonPanicPathOnly { + move_data.move_paths[init.path].place.as_local() + } else { + None + } + })); + } +} + +impl EverInitializedPlaces<'_, '_> { + /// Whether the init of `local` at `init` can reach `target` via a path that doesn't pass + /// through a `StorageDead(local)`. Mirrors the gen/kill structure of `EverInitializedPlaces`. + pub fn init_reaches_location( + body: &Body<'_>, + local: Local, + init: Init, + target: Location, + ) -> bool { + let init_loc = match init.location { + // Arguments are initialized on entry, and `StorageDead` is never emitted for them, so + // they reach every location. + InitLocation::Argument(_) => return true, + InitLocation::Statement(init_loc) => init_loc, + }; + + // Worklist of locations to walk forward from, seeded with the location(s) following `init`. + let mut queue = vec![]; + + let basic_blocks = &body.basic_blocks; + let init_block_data = &basic_blocks[init_loc.block]; + if init_loc.statement_index < init_block_data.statements.len() { + // This case mirrors `apply_primary_statement_effect`. + queue.push(init_loc.successor_within_block()); + } else if init.kind == InitKind::NonPanicPathOnly { + // This case mirrors `apply_call_return_effect`. + let TerminatorEdges::AssignOnReturn { return_, .. } = + init_block_data.terminator().edges() + else { + bug!("`NonPanicPathOnly` should only be seen on terminators with return edges"); + }; + queue.extend(return_.into_iter().map(BasicBlock::start_location)); + } else { + // This case mirrors `apply_primary_terminator_effect`. + queue.extend(init_block_data.terminator().successors().map(BasicBlock::start_location)); + } + + let mut visited = FxIndexSet::default(); + 'outer: while let Some(loc) = queue.pop() { + if !visited.insert(loc) { + continue; + } + // Walk from `loc` to the end of its block, looking for `target` or a kill. + let block_data = &basic_blocks[loc.block]; + for statement_index in loc.statement_index..=block_data.statements.len() { + if target == (Location { block: loc.block, statement_index }) { + return true; + } + if let Some(stmt) = block_data.statements.get(statement_index) + && let StatementKind::StorageDead(dead) = stmt.kind + && dead == local + { + continue 'outer; + } + } + + queue.extend(block_data.terminator().successors().map(BasicBlock::start_location)); } + false } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 07fb153b8da58..4a309607fdf4e 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -250,8 +250,9 @@ where let fut_ty = tcx .instantiate_bound_regions_with_erased( - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ty::new_fn_def(tcx, async_drop_fn_def_id, ty::Binder::dummy([drop_ty])).fn_sig(tcx), + tcx.fn_sig(async_drop_fn_def_id) + .instantiate(tcx, &[drop_ty.into()]) + .skip_norm_wip(), ) .output(); let fut = self.new_temp(fut_ty); @@ -373,7 +374,6 @@ where unwind_with_dead, vec![self.storage_live(fut)], TerminatorKind::Call { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) func: Operand::function_handle(tcx, async_drop_fn_def_id, &[drop_ty.into()], span), args: [dummy_spanned(drop_arg)].into(), destination: fut.into(), @@ -402,7 +402,6 @@ where func: Operand::function_handle( tcx, pin_obj_new_unchecked_fn, - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) &[obj_ref_ty.into()], span, ), @@ -568,7 +567,6 @@ where unwind, Vec::new(), TerminatorKind::Call { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) func: Operand::function_handle(tcx, poll_fn, &[fut_ty.into()], source_info.span), args: [ dummy_spanned(Operand::Move(fut_pin_local.into())), @@ -598,7 +596,6 @@ where func: Operand::function_handle( tcx, get_context_fn, - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) &[tcx.lifetimes.re_erased.into(), tcx.lifetimes.re_erased.into()], source_info.span, ), @@ -1252,7 +1249,6 @@ where ), )], TerminatorKind::Call { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) func: Operand::function_handle(tcx, drop_fn, &[ty.into()], self.source_info.span), args: [dummy_spanned(Operand::Move(Place::from(ref_place)))].into(), destination: unit_temp, diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 3311e82edf37f..9743d7b552862 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -325,7 +325,6 @@ pub fn build_drop_shim<'tcx>( start.terminator = Some(Terminator { source_info, kind: TerminatorKind::Call { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) func: Operand::function_handle( tcx, def_id, @@ -624,7 +623,6 @@ impl<'tcx> CloneShimBuilder<'tcx> { let tcx = self.tcx; // `func == Clone::clone(&ty) -> ty` - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) let func_ty = tcx.type_of(self.def_id).instantiate(tcx, &[ty.into()]).skip_norm_wip(); let func = Operand::Constant(Box::new(ConstOperand { span: self.span, diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index ad46b179bfed2..be1a7e1419a29 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -370,7 +370,6 @@ fn build_adrop_for_adrop_shim<'tcx>( Some(Terminator { source_info, kind: TerminatorKind::Call { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) func: Operand::function_handle(tcx, pin_fn, &[cor_ref.into()], span), args: [dummy_spanned(Operand::Move(cor_ref_place))].into(), destination: cor_pin_place, @@ -392,7 +391,6 @@ fn build_adrop_for_adrop_shim<'tcx>( Some(Terminator { source_info, kind: TerminatorKind::Call { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) func: Operand::function_handle(tcx, poll_fn, &[impl_ty.into()], span), args: [ dummy_spanned(Operand::Move(cor_pin_place)), diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 1e4e3a90f9c4a..560bb15a4db30 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -294,6 +294,7 @@ where relate_args_invariantly(self, a_args, b_args)?; Ok(a_ty) } + fn relate_with_variance>( &mut self, _variance: ty::Variance, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 96fb0c81a92d6..61baa4d838e36 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1129,6 +1129,11 @@ struct TypePrivacyVisitor<'tcx> { mod_id: LocalModId, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, span: Span, + /// Types already walked clean (no privacy error). A walk's result depends only on the + /// interned type and `mod_id`, which is fixed for the whole visit, so a type that walks + /// clean once walks clean everywhere and we can skip it. Errored walks are never cached, + /// so their error still fires at every span. + accessible_tys: FxHashSet>, } impl<'tcx> TypePrivacyVisitor<'tcx> { @@ -1136,6 +1141,15 @@ impl<'tcx> TypePrivacyVisitor<'tcx> { self.tcx.visibility(did).is_accessible_from(self.mod_id, self.tcx) } + fn check_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + if self.accessible_tys.contains(&ty) { + return ControlFlow::Continue(()); + } + self.visit(ty)?; + self.accessible_tys.insert(ty); + ControlFlow::Continue(()) + } + // Take node-id of an expression or pattern and check its type for privacy. fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool { self.span = span; @@ -1143,10 +1157,10 @@ impl<'tcx> TypePrivacyVisitor<'tcx> { .maybe_typeck_results .unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body")); try { - self.visit(typeck_results.node_type(id))?; + self.check_ty(typeck_results.node_type(id))?; self.visit(typeck_results.node_args(id))?; if let Some(adjustments) = typeck_results.adjustments().get(id) { - adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?; + adjustments.iter().try_for_each(|adjustment| self.check_ty(adjustment.target))?; } } .is_break() @@ -1179,14 +1193,11 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) { self.span = hir_ty.span; - if self - .visit( - self.maybe_typeck_results - .unwrap_or_else(|| span_bug!(hir_ty.span, "`hir::Ty` outside of a body")) - .node_type(hir_ty.hir_id), - ) - .is_break() - { + let ty = self + .maybe_typeck_results + .unwrap_or_else(|| span_bug!(hir_ty.span, "`hir::Ty` outside of a body")) + .node_type(hir_ty.hir_id); + if self.check_ty(ty).is_break() { return; } @@ -1205,7 +1216,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { .unwrap_or_else(|| span_bug!(inf_span, "Inference variable outside of a body")) .node_type_opt(inf_id) { - if self.visit(ty).is_break() { + if self.check_ty(ty).is_break() { return; } } else { @@ -1236,7 +1247,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { .unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body")); if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) { if self - .visit(self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip()) + .check_ty(self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip()) .is_break() { return; @@ -1750,7 +1761,13 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, mod_id: LocalModId) { // Check privacy of explicitly written types and traits as well as // inferred types of expressions and patterns. let span = tcx.def_span(mod_id); - let mut visitor = TypePrivacyVisitor { tcx, mod_id, maybe_typeck_results: None, span }; + let mut visitor = TypePrivacyVisitor { + tcx, + mod_id, + maybe_typeck_results: None, + span, + accessible_tys: Default::default(), + }; let module = tcx.hir_module_items(mod_id); for def_id in module.definitions() { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 32cc0200151f0..e0be35c34d303 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -329,7 +329,7 @@ pub struct Session { pub target: Target, pub host: Target, pub opts: config::Options, - pub target_tlib_path: Arc, + pub target_tlib_path: SearchPath, pub psess: ParseSess, pub unstable_features: UnstableFeatures, pub config: Cfg, @@ -396,8 +396,8 @@ pub struct Session { /// File paths accessed during the build. pub file_depinfo: Lock>, - target_filesearch: FileSearch, - host_filesearch: FileSearch, + target_filesearch: Arc, + host_filesearch: Arc, /// The names of intrinsics that the current codegen backend replaces /// with its own implementations. @@ -1328,15 +1328,8 @@ pub fn build_session( let host_triple = config::host_tuple(); let target_triple = sopts.target_triple.tuple(); // FIXME use host sysroot? - let host_tlib_path = - Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), host_triple)); - let target_tlib_path = if host_triple == target_triple { - // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary - // rescanning of the target lib path and an unnecessary allocation. - Arc::clone(&host_tlib_path) - } else { - Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), target_triple)) - }; + let host_tlib_path = SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), host_triple); + let target_tlib_path = SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), target_triple); let prof = SelfProfilerRef::new( self_profiler, @@ -1350,18 +1343,22 @@ pub fn build_session( }); let asm_arch = if target.allow_asm { InlineAsmArch::from_arch(&target.arch) } else { None }; - let target_filesearch = filesearch::FileSearch::new( + let target_filesearch = Arc::new(filesearch::FileSearch::new( &sopts.search_paths, &target_tlib_path, &target, sopts.unstable_opts.implicit_sysroot_deps, - ); - let host_filesearch = filesearch::FileSearch::new( - &sopts.search_paths, - &host_tlib_path, - &host, - sopts.unstable_opts.implicit_sysroot_deps, - ); + )); + let host_filesearch = if target == host { + Arc::clone(&target_filesearch) + } else { + Arc::new(filesearch::FileSearch::new( + &sopts.search_paths, + &host_tlib_path, + &host, + sopts.unstable_opts.implicit_sysroot_deps, + )) + }; let timings = TimingSectionHandler::new(sopts.json_timings); diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 1990ebd913eca..71228937a27f4 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -10,7 +10,6 @@ use rustc_infer::infer::canonical::{ }; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace}; use rustc_infer::traits::PredicateObligations; -use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; @@ -27,20 +26,120 @@ use crate::traits::{ StructurallyNormalizeExt, }; -#[extension(pub trait TraitEngineExt<'tcx, E>)] -impl<'tcx, E> dyn TraitEngine<'tcx, E> +/// A fulfillment engine, stored inline rather than boxed as a +/// `dyn TraitEngine` because some of its holders (e.g. [`ObligationCtxt`]) +/// are created very often (once per candidate probe during method +/// resolution), so the heap allocation would be expensive. +pub enum FulfillmentEngine<'tcx, E> { + Old(FulfillmentContext<'tcx, E>), + Next(NextFulfillmentCtxt<'tcx, E>), +} + +impl<'tcx, E> FulfillmentEngine<'tcx, E> where E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, { - fn new(infcx: &InferCtxt<'tcx>) -> Box { + pub fn new(infcx: &InferCtxt<'tcx>) -> Self { if infcx.next_trait_solver() { - Box::new(NextFulfillmentCtxt::new(infcx)) + FulfillmentEngine::Next(NextFulfillmentCtxt::new(infcx)) } else { assert!( !infcx.tcx.next_trait_solver_globally(), "using old solver even though new solver is enabled globally" ); - Box::new(FulfillmentContext::new(infcx)) + FulfillmentEngine::Old(FulfillmentContext::new(infcx)) + } + } +} + +impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentEngine<'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, +{ + fn register_predicate_obligation( + &mut self, + infcx: &InferCtxt<'tcx>, + obligation: PredicateObligation<'tcx>, + ) { + match self { + FulfillmentEngine::Old(engine) => { + engine.register_predicate_obligation(infcx, obligation) + } + FulfillmentEngine::Next(engine) => { + engine.register_predicate_obligation(infcx, obligation) + } + } + } + + fn register_predicate_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + obligations: PredicateObligations<'tcx>, + ) { + match self { + FulfillmentEngine::Old(engine) => { + engine.register_predicate_obligations(infcx, obligations) + } + FulfillmentEngine::Next(engine) => { + engine.register_predicate_obligations(infcx, obligations) + } + } + } + + fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { + match self { + FulfillmentEngine::Old(engine) => engine.try_evaluate_obligations(infcx), + FulfillmentEngine::Next(engine) => engine.try_evaluate_obligations(infcx), + } + } + + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { + match self { + FulfillmentEngine::Old(engine) => engine.collect_remaining_errors(infcx), + FulfillmentEngine::Next(engine) => engine.collect_remaining_errors(infcx), + } + } + + fn has_pending_obligations(&self) -> bool { + match self { + FulfillmentEngine::Old(engine) => engine.has_pending_obligations(), + FulfillmentEngine::Next(engine) => engine.has_pending_obligations(), + } + } + + fn pending_obligations(&self) -> PredicateObligations<'tcx> { + match self { + FulfillmentEngine::Old(engine) => engine.pending_obligations(), + FulfillmentEngine::Next(engine) => engine.pending_obligations(), + } + } + + fn pending_obligations_potentially_referencing_sub_root( + &self, + infcx: &InferCtxt<'tcx>, + sub_root: ty::TyVid, + ) -> PredicateObligations<'tcx> { + match self { + FulfillmentEngine::Old(engine) => { + engine.pending_obligations_potentially_referencing_sub_root(infcx, sub_root) + } + FulfillmentEngine::Next(engine) => { + engine.pending_obligations_potentially_referencing_sub_root(infcx, sub_root) + } + } + } + + fn drain_stalled_obligations_for_coroutines( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> PredicateObligations<'tcx> { + match self { + FulfillmentEngine::Old(engine) => { + engine.drain_stalled_obligations_for_coroutines(infcx) + } + FulfillmentEngine::Next(engine) => { + engine.drain_stalled_obligations_for_coroutines(infcx) + } } } } @@ -49,24 +148,24 @@ where /// with obligations outside of hir or mir typeck. pub struct ObligationCtxt<'a, 'tcx, E = ScrubbedTraitError<'tcx>> { pub infcx: &'a InferCtxt<'tcx>, - engine: RefCell>>, + engine: RefCell>, } impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>> { pub fn new_with_diagnostics(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(>::new(infcx)) } + Self { infcx, engine: RefCell::new(FulfillmentEngine::new(infcx)) } } } impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, ScrubbedTraitError<'tcx>> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(>::new(infcx)) } + Self { infcx, engine: RefCell::new(FulfillmentEngine::new(infcx)) } } } impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E> where - E: 'tcx, + E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, { pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); @@ -297,14 +396,14 @@ impl<'tcx> ObligationCtxt<'_, 'tcx, ScrubbedTraitError<'tcx>> { self.infcx.make_canonicalized_query_response( inference_vars, answer, - &mut **self.engine.borrow_mut(), + &mut *self.engine.borrow_mut(), ) } } impl<'tcx, E> ObligationCtxt<'_, 'tcx, E> where - E: FromSolverError<'tcx, NextSolverError<'tcx>>, + E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, { pub fn assumed_wf_types( &self, @@ -331,7 +430,7 @@ where match self .infcx .at(&cause, param_env) - .deeply_normalize(Unnormalized::new_wip(ty), &mut **self.engine.borrow_mut()) + .deeply_normalize(Unnormalized::new_wip(ty), &mut *self.engine.borrow_mut()) { // Insert well-formed types, ignoring duplicates. Ok(normalized) => drop(implied_bounds.insert(normalized)), @@ -348,7 +447,7 @@ where param_env: ty::ParamEnv<'tcx>, value: Unnormalized<'tcx, T>, ) -> Result> { - self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) + self.infcx.at(cause, param_env).deeply_normalize(value, &mut *self.engine.borrow_mut()) } pub fn structurally_normalize_ty( @@ -359,7 +458,7 @@ where ) -> Result, Vec> { self.infcx .at(cause, param_env) - .structurally_normalize_ty(value, &mut **self.engine.borrow_mut()) + .structurally_normalize_ty(value, &mut *self.engine.borrow_mut()) } pub fn structurally_normalize_const( @@ -370,7 +469,7 @@ where ) -> Result, Vec> { self.infcx .at(cause, param_env) - .structurally_normalize_const(value, &mut **self.engine.borrow_mut()) + .structurally_normalize_const(value, &mut *self.engine.borrow_mut()) } pub fn structurally_normalize_term( @@ -381,6 +480,6 @@ where ) -> Result, Vec> { self.infcx .at(cause, param_env) - .structurally_normalize_term(value, &mut **self.engine.borrow_mut()) + .structurally_normalize_term(value, &mut *self.engine.borrow_mut()) } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 76607a0107ecb..31eb756066a92 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -50,7 +50,7 @@ pub use self::dyn_compatibility::{ DynCompatibilityViolation, dyn_compatibility_violations_for_assoc_item, hir_ty_lowering_dyn_compatibility_violations, is_vtable_safe_method, }; -pub use self::engine::{ObligationCtxt, TraitEngineExt}; +pub use self::engine::{FulfillmentEngine, ObligationCtxt}; pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; pub use self::project::{normalize_inherent_projection, normalize_projection_term}; diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index a9ed6126ea752..7fd4b01b2b332 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -8,7 +8,7 @@ use tracing::{debug, instrument}; use crate::solve::NextSolverError; use crate::traits::query::NoSolution; use crate::traits::query::normalize::QueryNormalizeExt; -use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt}; +use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt, OldSolverError}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -106,7 +106,7 @@ pub fn compute_dropck_outlives_with_errors<'tcx, E>( span: Span, ) -> Result, Vec> where - E: FromSolverError<'tcx, NextSolverError<'tcx>>, + E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, { let tcx = ocx.infcx.tcx; let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal; diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 6abdaf404f103..461cfd30d1ffa 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -19,6 +19,7 @@ use rustc_infer::traits::Obligation; use rustc_middle::bug; use rustc_middle::query::LocalCrate; use rustc_middle::traits::query::NoSolution; +use rustc_middle::ty::fast_reject::{self, TreatParams}; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, @@ -394,7 +395,38 @@ pub(super) fn specialization_graph_provider( let mut sg = specialization_graph::Graph::new(); let overlap_mode = specialization_graph::OverlapMode::get(tcx, trait_id); - let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect(); + // Skip foreign non-blanket impls whose simplified-self bucket holds no + // local impl. This is sound because: + // - foreign impls are never overlap-checked, only recorded; `Ancestors` + // reads their parent lazily from metadata instead (the same value). + // - a local non-blanket impl is only compared against blanket impls and + // impls in its own bucket (see `filtered_children`), and instantiation + // preserves the simplified type, so kept buckets are complete at every + // level of the tree. + // - a local blanket impl, including alias self types which simplify to + // `None`, is compared against every child, so then all buckets are kept; + // pruning them would change error recovery (see impl-unpin.rs, `tait` + // revision). + let all_impls = tcx.trait_impls_of(trait_id); + let mut trait_impls: Vec = all_impls.blanket_impls().to_vec(); + let has_local_blanket_impl = + all_impls.blanket_impls().iter().any(|impl_def_id| impl_def_id.is_local()); + for (&simplified_self, bucket) in all_impls.non_blanket_impls() { + if has_local_blanket_impl || bucket.iter().any(|impl_def_id| impl_def_id.is_local()) { + trait_impls.extend(bucket.iter().copied()); + } else if cfg!(debug_assertions) { + // Assert metadata-derived key matches what the overlap checker recomputes. + for &impl_def_id in bucket { + let self_ty = tcx.impl_trait_ref(impl_def_id).skip_binder().self_ty(); + debug_assert_eq!( + fast_reject::simplify_type(tcx, self_ty, TreatParams::InstantiateWithInfer), + Some(simplified_self), + "trait_impls_of bucket key disagrees with overlap-check \ + simplification for foreign impl {impl_def_id:?}", + ); + } + } + } // The coherence checking implementation seems to rely on impls being // iterated over (roughly) in definition order, so we are sorting by diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index fa2e6154ce4f2..ccaf1550a6d31 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -66,8 +66,8 @@ pub trait TypeRelation: Sized { a_ty: I::Ty, b_ty: I::Ty, ty_def_id: I::DefId, - a_arg: I::GenericArgs, - b_arg: I::GenericArgs, + a_args: I::GenericArgs, + b_args: I::GenericArgs, mk: impl FnOnce(I::GenericArgs) -> I::Ty, ) -> RelateResult; @@ -503,12 +503,17 @@ pub fn structurally_relate_tys>( if a_args.skip_binder().is_empty() { Ok(a) } else { - let a_args = a_args.no_bound_vars().unwrap(); - let b_args = b_args.no_bound_vars().unwrap(); - relation.relate_ty_args(a, b, a_def_id.into(), a_args, b_args, |args| { - // FIXME(156581): actually instantiate the binder correctly (turbofishing/fndef changes) - Ty::new_fn_def(cx, a_def_id, ty::Binder::dummy(args)) - }) + // FIXME: this behavior is wrong; relations with binders needs fixing. + // need to relate the bound vars first. + let x = relation.relate_ty_args( + a, + b, + a_def_id.into(), + a_args.skip_binder(), + b_args.skip_binder(), + |args| Ty::new_fn_def(cx, a_def_id, a_args.rebind(args)), + ); + x } } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 930eaa965dfcf..d22f1bf038a7f 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -124,6 +124,7 @@ where combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |_| a_ty) } } + fn relate_with_variance>( &mut self, variance: ty::Variance, diff --git a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs index 740326d2f9420..93a08d3a12d49 100644 --- a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs @@ -65,8 +65,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, if let ty::FnDef(def_id, generics) = cast_from.kind() && let Some(method_name) = cx.tcx.opt_item_name(*def_id) - && let Some((const_name, ty_name)) = - get_const_name_and_ty_name(cx, method_name, *def_id, generics.no_bound_vars().unwrap().as_slice()) + && let Some((const_name, ty_name)) = get_const_name_and_ty_name(cx, method_name, *def_id, generics.no_bound_vars().unwrap().as_slice()) { let mut applicability = Applicability::MaybeIncorrect; let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability); diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr index 664bab4b62f6d..7998db2424b36 100644 --- a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr +++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reference not dereferenceable: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | *num += 1; diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 3f066b6565880..50f041931aea9 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: reference not dereferenceable: reference must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { *(&*x as *const u32) }; - | ^^^ Undefined Behavior occurred here + | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr index 83451d00daecf..3faff2248e408 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reference not dereferenceable: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/stack_temporary.rs:LL:CC | LL | let val = *x; diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index f55c904425510..dc3565ce399be 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reference not dereferenceable: reference must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC | LL | let _x = unsafe { *&mut *(LEAK as *mut i32) }; diff --git a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr index 6d9cd81f3f802..b0f9ffb451973 100644 --- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr +++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: reference not dereferenceable: reference must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/pointer_partial_overwrite.rs:LL:CC | LL | let x = *p; diff --git a/src/tools/miri/tests/fail/rc_as_ptr.stderr b/src/tools/miri/tests/fail/rc_as_ptr.stderr index c86ee3300f03c..42bf8637e0da8 100644 --- a/src/tools/miri/tests/fail/rc_as_ptr.stderr +++ b/src/tools/miri/tests/fail/rc_as_ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: box not dereferenceable: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/rc_as_ptr.rs:LL:CC | LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index 229d515ffdd18..8847c6a69bb79 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -156,9 +156,9 @@ pub fn type_parameter() {} pub fn lifetime_parameter () {} #[cfg(not(any(bpass1,bpass4)))] -#[rustc_clean(cfg = "bpass2", except = "hir_owner, generics_of,fn_sig")] +#[rustc_clean(cfg = "bpass2", except = "hir_owner, generics_of, fn_sig, type_of")] #[rustc_clean(cfg = "bpass3")] -#[rustc_clean(cfg = "bpass5", except = "hir_owner, generics_of,fn_sig")] +#[rustc_clean(cfg = "bpass5", except = "hir_owner, generics_of, fn_sig, type_of")] #[rustc_clean(cfg = "bpass6")] pub fn lifetime_parameter<'a>() {} diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs index ade4554372cc1..e2261f779a2e8 100644 --- a/tests/incremental/hashes/inherent_impls.rs +++ b/tests/incremental/hashes/inherent_impls.rs @@ -146,12 +146,12 @@ impl Foo { impl Foo { #[rustc_clean( cfg="bpass2", - except="hir_owner,fn_sig,generics_of,typeck_root,associated_item,optimized_mir", + except="hir_owner,fn_sig,type_of,generics_of,typeck_root,associated_item,optimized_mir", )] #[rustc_clean(cfg="bpass3")] #[rustc_clean( cfg="bpass5", - except="hir_owner,fn_sig,generics_of,typeck_root,associated_item,optimized_mir", + except="hir_owner,fn_sig,type_of,generics_of,typeck_root,associated_item,optimized_mir", )] #[rustc_clean(cfg="bpass6")] pub fn method_selfness(&self) { } @@ -421,9 +421,9 @@ impl Foo { // ---------------------------------------------------------- // ----------------------------------------------------------- // ---------------------------------------------------------- - // -------------------------------------------------------------- + // ---------------------------------------------------------------------- // ------------------------- - // -------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- // ------------------------- pub fn add_lifetime_parameter_to_method (&self) { } } @@ -443,9 +443,9 @@ impl Foo { // if we lower generics before the body, then the `HirId` for // things in the body will be affected. So if you start to see // `typeck_root` appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="bpass2", except="hir_owner,fn_sig")] + #[rustc_clean(cfg="bpass2", except="hir_owner,fn_sig,type_of")] #[rustc_clean(cfg="bpass3")] - #[rustc_clean(cfg="bpass5", except="hir_owner,fn_sig,generics_of")] + #[rustc_clean(cfg="bpass5", except="hir_owner,fn_sig,type_of,generics_of")] #[rustc_clean(cfg="bpass6")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } diff --git a/tests/incremental/hashes/trait_defs.rs b/tests/incremental/hashes/trait_defs.rs index 3c6021105e893..f9c1be94d5e30 100644 --- a/tests/incremental/hashes/trait_defs.rs +++ b/tests/incremental/hashes/trait_defs.rs @@ -380,9 +380,9 @@ trait TraitChangeModeSelfOwnToRef { #[rustc_clean(except="hir_owner,clauses_of", cfg="bpass5")] #[rustc_clean(cfg="bpass6")] trait TraitChangeModeSelfOwnToRef { - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="bpass2")] + #[rustc_clean(except="hir_owner,fn_sig,type_of,generics_of", cfg="bpass2")] #[rustc_clean(cfg="bpass3")] - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="bpass5")] + #[rustc_clean(except="hir_owner,fn_sig,type_of,generics_of", cfg="bpass5")] #[rustc_clean(cfg="bpass6")] fn method(&self); } @@ -509,9 +509,9 @@ trait TraitAddLifetimeParameterToMethod { #[rustc_clean(except="hir_owner,clauses_of", cfg="bpass5")] #[rustc_clean(cfg="bpass6")] trait TraitAddLifetimeParameterToMethod { - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="bpass2")] + #[rustc_clean(except="hir_owner,fn_sig,type_of,generics_of", cfg="bpass2")] #[rustc_clean(cfg="bpass3")] - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="bpass5")] + #[rustc_clean(except="hir_owner,fn_sig,type_of,generics_of", cfg="bpass5")] #[rustc_clean(cfg="bpass6")] fn method<'a>(); } diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs index 989cae1939622..9698ec0473c4b 100644 --- a/tests/incremental/hashes/trait_impls.rs +++ b/tests/incremental/hashes/trait_impls.rs @@ -148,12 +148,12 @@ pub trait ChangeMethodSelfnessTrait { #[rustc_clean(cfg="bpass6")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_clean( - except="hir_owner,associated_item,generics_of,fn_sig,typeck_root,optimized_mir", + except="hir_owner,associated_item,generics_of,fn_sig,type_of,typeck_root,optimized_mir", cfg="bpass2", )] #[rustc_clean(cfg="bpass3")] #[rustc_clean( - except="hir_owner,associated_item,generics_of,fn_sig,typeck_root,optimized_mir", + except="hir_owner,associated_item,generics_of,fn_sig,type_of,typeck_root,optimized_mir", cfg="bpass5", )] #[rustc_clean(cfg="bpass6")] @@ -186,12 +186,12 @@ pub trait RemoveMethodSelfnessTrait { #[rustc_clean(cfg="bpass6")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_clean( - except="hir_owner,associated_item,generics_of,fn_sig,typeck_root,optimized_mir", + except="hir_owner,associated_item,generics_of,fn_sig,type_of,typeck_root,optimized_mir", cfg="bpass2", )] #[rustc_clean(cfg="bpass3")] #[rustc_clean( - except="hir_owner,associated_item,generics_of,fn_sig,typeck_root,optimized_mir", + except="hir_owner,associated_item,generics_of,fn_sig,type_of,typeck_root,optimized_mir", cfg="bpass5", )] #[rustc_clean(cfg="bpass6")] diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs index 7c2d86bff75b2..fcb0dccf750e3 100644 --- a/tests/ui/const-ptr/forbidden_slices.rs +++ b/tests/ui/const-ptr/forbidden_slices.rs @@ -20,7 +20,7 @@ pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; // Out of bounds pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; -//~^ ERROR: reference must be dereferenceable for 8 bytes +//~^ ERROR: dangling reference (going beyond the bounds of its allocation) // Reading uninitialized data pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; //~ ERROR: uninitialized memory @@ -39,14 +39,14 @@ pub static S7: &[u16] = unsafe { // Unaligned read pub static S8: &[u64] = unsafe { + //~^ ERROR: dangling reference (going beyond the bounds of its allocation) let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::(); from_raw_parts(ptr, 1) - //~^ ERROR: reference must be dereferenceable for 8 bytes }; pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; -//~^ ERROR: null reference +//~^ ERROR encountered a null reference pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore //~^ ERROR 0 < pointee_size && pointee_size <= isize::MAX as usize pub static R2: &[u32] = unsafe { @@ -70,9 +70,9 @@ pub static R6: &[bool] = unsafe { from_ptr_range(ptr..ptr.add(4)) }; pub static R7: &[u16] = unsafe { + //~^ ERROR: unaligned reference (required 2 byte alignment but found 1) let ptr = (&D2 as *const Struct as *const u16).byte_add(1); from_ptr_range(ptr..ptr.add(4)) - //~^ ERROR: unaligned reference (required 2 byte alignment but found 1) }; pub static R8: &[u64] = unsafe { let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::(); diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index fb5b9c9764076..e23b4e5b1aa75 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -1,20 +1,35 @@ -error[E0080]: dereferencing a null reference - --> $DIR/forbidden_slices.rs:16:34 +error[E0080]: constructing invalid value of type &[u32]: encountered a null reference + --> $DIR/forbidden_slices.rs:16:1 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `S0` failed here + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } -error[E0080]: dereferencing a null reference - --> $DIR/forbidden_slices.rs:18:33 +error[E0080]: constructing invalid value of type &[()]: encountered a null reference + --> $DIR/forbidden_slices.rs:18:1 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `S1` failed here + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } -error[E0080]: reference not dereferenceable: reference must be dereferenceable for 8 bytes, but got ALLOC$ID which is only 4 bytes from the end of the allocation - --> $DIR/forbidden_slices.rs:22:34 +error[E0080]: constructing invalid value of type &[u32]: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/forbidden_slices.rs:22:1 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `S2` failed here + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ HEX_DUMP + } error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:26:1 @@ -62,17 +77,27 @@ LL | pub static S7: &[u16] = unsafe { ╾ALLOC$ID╼ HEX_DUMP } -error[E0080]: reference not dereferenceable: reference must be dereferenceable for 8 bytes, but got ALLOC$ID+0x1 which is only 7 bytes from the end of the allocation - --> $DIR/forbidden_slices.rs:44:5 +error[E0080]: constructing invalid value of type &[u64]: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/forbidden_slices.rs:41:1 | -LL | from_raw_parts(ptr, 1) - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `S8` failed here +LL | pub static S8: &[u64] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ HEX_DUMP + } -error[E0080]: dereferencing a null reference - --> $DIR/forbidden_slices.rs:48:34 +error[E0080]: constructing invalid value of type &[u32]: encountered a null reference + --> $DIR/forbidden_slices.rs:48:1 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `R0` failed here + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: evaluation panicked: assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize --> $DIR/forbidden_slices.rs:50:33 @@ -121,11 +146,16 @@ LL | pub static R6: &[bool] = unsafe { ╾ALLOC$ID╼ HEX_DUMP } -error[E0080]: encountered an unaligned reference (required 2 byte alignment but found 1) - --> $DIR/forbidden_slices.rs:74:5 +error[E0080]: constructing invalid value of type &[u16]: encountered an unaligned reference (required 2 byte alignment but found 1) + --> $DIR/forbidden_slices.rs:72:1 + | +LL | pub static R7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | -LL | from_ptr_range(ptr..ptr.add(4)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `R7` failed here + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ HEX_DUMP + } error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC$ID+0x1 which is only 7 bytes from the end of the allocation --> $DIR/forbidden_slices.rs:79:25 diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs index 5609fb56a1322..80cf3ffef11a5 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -10,10 +10,10 @@ use std::intrinsics; const _X: &'static u8 = unsafe { + //~^ ERROR: dangling reference (use-after-free) let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 4, 4); &*ptr - //~^ ERROR: this pointer is dangling }; const _Y: u8 = unsafe { diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index 01fe36c0a537a..e9b7f99ee6d99 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -1,10 +1,15 @@ -error[E0080]: reference not dereferenceable: ALLOC$ID has been freed, so this pointer is dangling - --> $DIR/dealloc_intrinsic_dangling.rs:15:5 +error[E0080]: constructing invalid value of type &u8: encountered a dangling reference (use-after-free) + --> $DIR/dealloc_intrinsic_dangling.rs:12:1 | -LL | &*ptr - | ^^^^^ evaluation of `_X` failed here +LL | const _X: &'static u8 = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ │ ╾─╼ + } -error[E0080]: reference not dereferenceable: ALLOC$ID has been freed, so this pointer is dangling +error[E0080]: memory access failed: ALLOC$ID has been freed, so this pointer is dangling --> $DIR/dealloc_intrinsic_dangling.rs:23:5 | LL | *reference diff --git a/tests/ui/consts/const-eval/issue-49296.stderr b/tests/ui/consts/const-eval/issue-49296.stderr index 90e8176d79c59..64e892e61af47 100644 --- a/tests/ui/consts/const-eval/issue-49296.stderr +++ b/tests/ui/consts/const-eval/issue-49296.stderr @@ -1,4 +1,4 @@ -error[E0080]: reference not dereferenceable: ALLOC$ID has been freed, so this pointer is dangling +error[E0080]: memory access failed: ALLOC$ID has been freed, so this pointer is dangling --> $DIR/issue-49296.rs:9:16 | LL | const X: u64 = *wat(42); diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index c9f1e5f1639bb..8dbb05c15725a 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -1,11 +1,8 @@ -error[E0080]: reference not dereferenceable: reference must be dereferenceable for 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/nonnull_as_ref_ub.rs:4:39 +error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^ evaluation of `_` failed inside this call - | -note: inside `NonNull::::as_ref::<'_>` - --> $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 70ca9dbcd1037..1efd30818b2e5 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -1,14 +1,24 @@ -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-incorrect-vtable.rs:19:14 +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:18:1 | -LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `INVALID_VTABLE_ALIGNMENT` failed here +LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾──╼╾──╼ + } -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-incorrect-vtable.rs:23:14 +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:22:1 | -LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `INVALID_VTABLE_SIZE` failed here +LL | const INVALID_VTABLE_SIZE: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾──╼╾──╼ + } error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC$ID, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:31:1 diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index b4e1be920b8f3..bc26c93513964 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -1,14 +1,24 @@ -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-incorrect-vtable.rs:19:14 +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:18:1 | -LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `INVALID_VTABLE_ALIGNMENT` failed here +LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾──────╼╾──────╼ + } -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-incorrect-vtable.rs:23:14 +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:22:1 | -LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `INVALID_VTABLE_SIZE` failed here +LL | const INVALID_VTABLE_SIZE: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾──────╼╾──────╼ + } error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC$ID, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:31:1 diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs index b7a49f5fe78e7..4185b0261b296 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -17,11 +17,11 @@ trait Trait {} const INVALID_VTABLE_ALIGNMENT: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; -//~^ ERROR vtable +//~^^ ERROR vtable const INVALID_VTABLE_SIZE: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; -//~^ ERROR vtable +//~^^ ERROR vtable #[repr(transparent)] struct W(T); diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index 64b13f91e839b..327a5689de062 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -140,11 +140,11 @@ const DYN_METADATA: ptr::DynMetadata = ptr::metadata::(ptr:: static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - //~^ ERROR null pointer + //~^^ ERROR null pointer }; static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - //~^ ERROR vtable + //~^^ ERROR vtable }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index 10c6dafeac7cd..b442a43c6276f 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -226,23 +226,38 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u ╾ALLOC$ID╼ HEX_DUMP } -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-wide-ptr.rs:119:57 +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:119:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TRAIT_OBJ_UNALIGNED_VTABLE` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾─╼ + } -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-wide-ptr.rs:121:57 +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:121:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TRAIT_OBJ_BAD_DROP_FN_NULL` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾─╼ + } -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-wide-ptr.rs:123:56 +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TRAIT_OBJ_BAD_DROP_FN_INT` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾─╼ + } error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC$ID, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:125:1 @@ -288,17 +303,27 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾─╼ } -error[E0080]: using null pointer as vtable pointer but it does not point to a vtable - --> $DIR/ub-wide-ptr.rs:142:5 +error[E0080]: constructing invalid value of type *const dyn Trait: encountered null pointer, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:141:1 + | +LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | -LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF` failed here + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ HEX_DUMP + } -error[E0080]: using ALLOC$ID as vtable pointer but it does not point to a vtable - --> $DIR/ub-wide-ptr.rs:146:5 +error[E0080]: constructing invalid value of type *const dyn Trait: encountered ALLOC$ID, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:145:1 | -LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF` failed here +LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + ╾ALLOC$ID╼ ╾ALLOC$ID╼ │ ╾─╼ + } error: aborting due to 29 previous errors diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs index 3438790232fe5..ebf1f88eb8e72 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -84,8 +84,8 @@ fn dangling() { // Undefined behaviour (integer as pointer), who doesn't love tests like this. Some(&mut *(42 as *mut i32)) } } - const INT2PTR: Option<&mut i32> = helper_int2ptr(); //~ ERROR reference not dereferenceable - static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); //~ ERROR reference not dereferenceable + const INT2PTR: Option<&mut i32> = helper_int2ptr(); //~ ERROR encountered a dangling reference + static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); //~ ERROR encountered a dangling reference const fn helper_dangling() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (dangling pointer), who doesn't love tests like this. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index d631dd3376086..ad19f78ef831b 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -120,29 +120,27 @@ LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; = note: to avoid accidentally creating global mutable state, such temporaries must be immutable = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` -error[E0080]: reference not dereferenceable: reference must be dereferenceable for 4 bytes, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/mut_ref_in_final.rs:87:39 +error[E0080]: constructing invalid value of type Option<&mut i32>: at ..0, encountered a dangling reference (0x2a[noalloc] has no provenance) + --> $DIR/mut_ref_in_final.rs:87:5 | LL | const INT2PTR: Option<&mut i32> = helper_int2ptr(); - | ^^^^^^^^^^^^^^^^ evaluation of `dangling::INT2PTR` failed inside this call + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | -note: inside `helper_int2ptr` - --> $DIR/mut_ref_in_final.rs:85:14 - | -LL | Some(&mut *(42 as *mut i32)) - | ^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } -error[E0080]: reference not dereferenceable: reference must be dereferenceable for 4 bytes, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) - --> $DIR/mut_ref_in_final.rs:88:47 +error[E0080]: constructing invalid value of type Option<&mut i32>: at ..0, encountered a dangling reference (0x2a[noalloc] has no provenance) + --> $DIR/mut_ref_in_final.rs:88:5 | LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); - | ^^^^^^^^^^^^^^^^ evaluation of `dangling::INT2PTR_STATIC` failed inside this call + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | -note: inside `helper_int2ptr` - --> $DIR/mut_ref_in_final.rs:85:14 - | -LL | Some(&mut *(42 as *mut i32)) - | ^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: constructing invalid value of type Option<&mut i32>: at ..0, encountered a dangling reference (use-after-free) --> $DIR/mut_ref_in_final.rs:94:5 diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index a809e7c265d22..268527c0e5bf8 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -17,11 +17,11 @@ LL | std::intrinsics::raw_eq(&(&0), &(&1)) = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: encountered an unaligned reference (required 4 byte alignment but found 1) - --> $DIR/intrinsic-raw_eq-const-bad.rs:17:29 +error[E0080]: accessing memory with alignment 1, but alignment 4 is required + --> $DIR/intrinsic-raw_eq-const-bad.rs:17:5 | LL | std::intrinsics::raw_eq(aref, aref) - | ^^^^ evaluation of `RAW_EQ_NOT_ALIGNED` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_NOT_ALIGNED` failed here error: aborting due to 3 previous errors diff --git a/tests/ui/thir-print/thir-tree-match-for.stdout b/tests/ui/thir-print/thir-tree-match-for.stdout index ac71f6a1d1f07..5e32526fc5633 100644 --- a/tests/ui/thir-print/thir-tree-match-for.stdout +++ b/tests/ui/thir-print/thir-tree-match-for.stdout @@ -560,12 +560,12 @@ body: span: $DIR/thir-tree-match-for.rs:16:12: 16:16 (#7) kind: Call { - ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [] }) + ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [Region(BrNamed(DefId(N:M ~ core::iter::traits::iterator::Iterator::next::'_)))] }) from_hir_call: true fn_span: $DIR/thir-tree-match-for.rs:16:12: 16:16 (#7) fun: Expr { - ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [] }) + ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [Region(BrNamed(DefId(N:M ~ core::iter::traits::iterator::Iterator::next::'_)))] }) temp_scope_id: 34 span: $DIR/thir-tree-match-for.rs:16:12: 16:16 (#7) kind: @@ -574,7 +574,7 @@ body: hir_id: HirId(DefId(N:M ~ thir_tree_match_for::match_from_for).34) value: Expr { - ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [] }) + ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [Region(BrNamed(DefId(N:M ~ core::iter::traits::iterator::Iterator::next::'_)))] }) temp_scope_id: 34 span: $DIR/thir-tree-match-for.rs:16:12: 16:16 (#7) kind: @@ -1117,12 +1117,12 @@ body: span: $DIR/thir-tree-match-for.rs:25:13: 25:38 (#0) kind: Call { - ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [] }) + ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [Region(BrNamed(DefId(N:M ~ core::iter::traits::iterator::Iterator::next::'_)))] }) from_hir_call: true fn_span: $DIR/thir-tree-match-for.rs:25:13: 25:38 (#0) fun: Expr { - ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [] }) + ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [Region(BrNamed(DefId(N:M ~ core::iter::traits::iterator::Iterator::next::'_)))] }) temp_scope_id: 25 span: $DIR/thir-tree-match-for.rs:25:13: 25:27 (#0) kind: @@ -1131,7 +1131,7 @@ body: hir_id: HirId(DefId(N:M ~ thir_tree_match_for::match_loop_nonfor).25) value: Expr { - ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [] }) + ty: FnDef(DefId(N:M ~ core::iter::traits::iterator::Iterator::next), Binder { value: [std::ops::Range], bound_vars: [Region(BrNamed(DefId(N:M ~ core::iter::traits::iterator::Iterator::next::'_)))] }) temp_scope_id: 25 span: $DIR/thir-tree-match-for.rs:25:13: 25:27 (#0) kind: