about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe Miri Conjob Bot <miri@cron.bot>2023-08-03 05:32:12 +0000
committerThe Miri Conjob Bot <miri@cron.bot>2023-08-03 05:32:12 +0000
commitadb446cc0741834aa55633c40993b87ad299d310 (patch)
treeb6df8166640dece38e0bf65dd01a2649386cf7fb
parent072835472ae5794d533edafe9acd6d14082b31f2 (diff)
parentd8bbef50bbad789e26219f4ec88b5d73b05570a3 (diff)
downloadrust-adb446cc0741834aa55633c40993b87ad299d310.tar.gz
rust-adb446cc0741834aa55633c40993b87ad299d310.zip
Merge from rustc
-rw-r--r--compiler/rustc_ast/src/format.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/var_name.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs27
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs194
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs204
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs2
-rw-r--r--compiler/rustc_const_eval/src/errors.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs23
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/object_safety.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs42
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs8
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs2
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs7
-rw-r--r--compiler/rustc_infer/src/traits/util.rs6
-rw-r--r--compiler/rustc_lint/messages.ftl6
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lints.rs14
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs113
-rw-r--r--compiler/rustc_metadata/messages.ftl3
-rw-r--r--compiler/rustc_metadata/src/errors.rs16
-rw-r--r--compiler/rustc_metadata/src/locator.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs4
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs65
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs13
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs1
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs42
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs10
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs40
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs8
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs8
-rw-r--r--library/core/src/cell.rs3
-rw-r--r--library/core/src/ffi/c_str.rs13
-rw-r--r--src/bootstrap/format.rs31
-rw-r--r--src/bootstrap/llvm.rs9
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/librustdoc/clean/utils.rs6
-rw-r--r--src/tools/build_helper/src/git.rs38
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs16
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs62
-rw-r--r--src/tools/miri/src/concurrency/sync.rs2
-rw-r--r--src/tools/miri/src/helpers.rs22
-rw-r--r--src/tools/miri/src/shims/backtrace.rs2
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/intrinsics/atomic.rs10
-rw-r--r--src/tools/miri/src/shims/intrinsics/mod.rs4
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs4
-rw-r--r--src/tools/miri/src/shims/time.rs14
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs16
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs10
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd.rs4
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs2
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs2
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs34
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs2
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs10
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs2
-rw-r--r--src/tools/miri/src/shims/windows/thread.rs2
-rw-r--r--src/tools/miri/tests/fail/alloc/deallocate-twice.rs2
-rw-r--r--src/tools/miri/tests/fail/alloc/deallocate-twice.stderr4
-rw-r--r--src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs2
-rw-r--r--src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr4
-rw-r--r--src/tools/miri/tests/fail/alloc/reallocate-dangling.rs2
-rw-r--r--src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/illegal_write1.rs2
-rw-r--r--src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.rs2
-rw-r--r--src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs11
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr15
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs (renamed from src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.rs)2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr (renamed from src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.stderr)8
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/stack_temporary.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr4
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs2
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr4
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs2
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr4
-rw-r--r--src/tools/miri/tests/fail/environ-gets-deallocated.rs2
-rw-r--r--src/tools/miri/tests/fail/environ-gets-deallocated.stderr4
-rw-r--r--src/tools/miri/tests/fail/generator-pinned-moved.rs2
-rw-r--r--src/tools/miri/tests/fail/generator-pinned-moved.stderr4
-rw-r--r--src/tools/miri/tests/fail/rc_as_ptr.rs2
-rw-r--r--src/tools/miri/tests/fail/rc_as_ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/shims/mmap_use_after_munmap.rs2
-rw-r--r--src/tools/miri/tests/fail/shims/mmap_use_after_munmap.stderr4
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/illegal_write3.rs2
-rw-r--r--src/tools/miri/tests/fail/zst2.rs2
-rw-r--r--src/tools/miri/tests/fail/zst2.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-100313.rs1
-rw-r--r--tests/ui/const-generics/issues/issue-100313.stderr12
-rw-r--r--tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr4
-rw-r--r--tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr2
-rw-r--r--tests/ui/consts/const-eval/issue-49296.stderr2
-rw-r--r--tests/ui/consts/const-float-classify.rs3
-rw-r--r--tests/ui/consts/const-float-classify.stderr11
-rw-r--r--tests/ui/consts/constifconst-call-in-const-position.stderr18
-rw-r--r--tests/ui/consts/ptr_comparisons.rs36
-rw-r--r--tests/ui/consts/ptr_comparisons.stderr40
-rw-r--r--tests/ui/consts/unstable-const-fn-in-libcore.rs1
-rw-r--r--tests/ui/consts/unstable-const-fn-in-libcore.stderr17
-rw-r--r--tests/ui/generic-const-items/const-trait-impl.rs3
-rw-r--r--tests/ui/generic-const-items/const-trait-impl.stderr11
-rw-r--r--tests/ui/impl-trait/normalize-tait-in-const.stderr17
-rw-r--r--tests/ui/imports/resolve-other-libc.rs14
-rw-r--r--tests/ui/imports/resolve-other-libc.stderr8
-rw-r--r--tests/ui/lint/reference_casting.rs94
-rw-r--r--tests/ui/lint/reference_casting.stderr102
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr20
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr39
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr21
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr13
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr13
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr14
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs1
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr51
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr11
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.stderr11
203 files changed, 1264 insertions, 1119 deletions
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
index 699946f307b..805596ff00a 100644
--- a/compiler/rustc_ast/src/format.rs
+++ b/compiler/rustc_ast/src/format.rs
@@ -67,12 +67,6 @@ pub struct FormatArguments {
     names: FxHashMap<Symbol, usize>,
 }
 
-// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
-#[cfg(parallel_compiler)]
-unsafe impl Sync for FormatArguments {}
-#[cfg(parallel_compiler)]
-unsafe impl Send for FormatArguments {}
-
 impl FormatArguments {
     pub fn new() -> Self {
         Self {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 9cad8fa5318..be6eb2d1d12 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -886,6 +886,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             .universal_regions()
             .defining_ty
             .upvar_tys()
+            .iter()
             .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region))
         {
             let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 98418e2372f..8832d345df2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -43,7 +43,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         fr: RegionVid,
     ) -> Option<usize> {
         let upvar_index =
-            self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
+            self.universal_regions().defining_ty.upvar_tys().iter().position(|upvar_ty| {
                 debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}");
                 tcx.any_free_region_meets(&upvar_ty, |r| {
                     let r = r.as_var();
@@ -52,7 +52,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 })
             })?;
 
-        let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index);
+        let upvar_ty = self.universal_regions().defining_ty.upvar_tys().get(upvar_index);
 
         debug!(
             "get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}",
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index c19fbf20ca5..16f5e68a06f 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -90,11 +90,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     ) {
         self.prove_predicate(
             ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait(
-                ty::TraitPredicate {
-                    trait_ref,
-                    constness: ty::BoundConstness::NotConst,
-                    polarity: ty::ImplPolarity::Positive,
-                },
+                ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive },
             ))),
             locations,
             category,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index fd4a3ec1a5e..abb11ce7396 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -791,25 +791,20 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                     (adt_def.variant(FIRST_VARIANT), args)
                 }
                 ty::Closure(_, args) => {
-                    return match args
-                        .as_closure()
-                        .tupled_upvars_ty()
-                        .tuple_fields()
-                        .get(field.index())
-                    {
+                    return match args.as_closure().upvar_tys().get(field.index()) {
                         Some(&ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
-                            field_count: args.as_closure().upvar_tys().count(),
+                            field_count: args.as_closure().upvar_tys().len(),
                         }),
                     };
                 }
                 ty::Generator(_, args, _) => {
                     // Only prefix fields (upvars and current state) are
                     // accessible without a variant index.
-                    return match args.as_generator().prefix_tys().nth(field.index()) {
-                        Some(ty) => Ok(ty),
+                    return match args.as_generator().prefix_tys().get(field.index()) {
+                        Some(ty) => Ok(*ty),
                         None => Err(FieldAccessError::OutOfRange {
-                            field_count: args.as_generator().prefix_tys().count(),
+                            field_count: args.as_generator().prefix_tys().len(),
                         }),
                     };
                 }
@@ -1772,10 +1767,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
             AggregateKind::Closure(_, args) => {
-                match args.as_closure().upvar_tys().nth(field_index.as_usize()) {
-                    Some(ty) => Ok(ty),
+                match args.as_closure().upvar_tys().get(field_index.as_usize()) {
+                    Some(ty) => Ok(*ty),
                     None => Err(FieldAccessError::OutOfRange {
-                        field_count: args.as_closure().upvar_tys().count(),
+                        field_count: args.as_closure().upvar_tys().len(),
                     }),
                 }
             }
@@ -1783,10 +1778,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // It doesn't make sense to look at a field beyond the prefix;
                 // these require a variant index, and are not initialized in
                 // aggregate rvalues.
-                match args.as_generator().prefix_tys().nth(field_index.as_usize()) {
-                    Some(ty) => Ok(ty),
+                match args.as_generator().prefix_tys().get(field_index.as_usize()) {
+                    Some(ty) => Ok(*ty),
                     None => Err(FieldAccessError::OutOfRange {
-                        field_count: args.as_generator().prefix_tys().count(),
+                        field_count: args.as_generator().prefix_tys().len(),
                     }),
                 }
             }
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index a751a9732f0..56945f43fcd 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -12,7 +12,6 @@
 //! The code in this file doesn't *do anything* with those results; it
 //! just returns them for other code to use.
 
-use either::Either;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Diagnostic;
 use rustc_hir as hir;
@@ -115,14 +114,12 @@ impl<'tcx> DefiningTy<'tcx> {
     /// not a closure or generator, there are no upvars, and hence it
     /// will be an empty list. The order of types in this list will
     /// match up with the upvar order in the HIR, typesystem, and MIR.
-    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+    pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
         match self {
-            DefiningTy::Closure(_, args) => Either::Left(args.as_closure().upvar_tys()),
-            DefiningTy::Generator(_, args, _) => {
-                Either::Right(Either::Left(args.as_generator().upvar_tys()))
-            }
+            DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
+            DefiningTy::Generator(_, args, _) => args.as_generator().upvar_tys(),
             DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
-                Either::Right(Either::Right(iter::empty()))
+                ty::List::empty()
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 6ca61aa43d7..7a82d05ce9e 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -85,3 +85,197 @@ impl CounterExpression {
         Self { kind, lhs, rhs }
     }
 }
+
+/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
+///
+/// Must match the layout of `LLVMRustCounterMappingRegionKind`.
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub enum RegionKind {
+    /// A CodeRegion associates some code with a counter
+    CodeRegion = 0,
+
+    /// An ExpansionRegion represents a file expansion region that associates
+    /// a source range with the expansion of a virtual source file, such as
+    /// for a macro instantiation or #include file.
+    ExpansionRegion = 1,
+
+    /// A SkippedRegion represents a source range with code that was skipped
+    /// by a preprocessor or similar means.
+    SkippedRegion = 2,
+
+    /// A GapRegion is like a CodeRegion, but its count is only set as the
+    /// line execution count when its the only region in the line.
+    GapRegion = 3,
+
+    /// A BranchRegion represents leaf-level boolean expressions and is
+    /// associated with two counters, each representing the number of times the
+    /// expression evaluates to true or false.
+    BranchRegion = 4,
+}
+
+/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
+/// coverage map, in accordance with the
+/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+/// The struct composes fields representing the `Counter` type and value(s) (injected counter
+/// ID, or expression type and operands), the source file (an indirect index into a "filenames
+/// array", encoded separately), and source location (start and end positions of the represented
+/// code region).
+///
+/// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
+///
+/// Must match the layout of `LLVMRustCounterMappingRegion`.
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct CounterMappingRegion {
+    /// The counter type and type-dependent counter data, if any.
+    counter: Counter,
+
+    /// If the `RegionKind` is a `BranchRegion`, this represents the counter
+    /// for the false branch of the region.
+    false_counter: Counter,
+
+    /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
+    /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
+    /// that, in turn, are used to look up the filename for this region.
+    file_id: u32,
+
+    /// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find
+    /// the mapping regions created as a result of macro expansion, by checking if their file id
+    /// matches the expanded file id.
+    expanded_file_id: u32,
+
+    /// 1-based starting line of the mapping region.
+    start_line: u32,
+
+    /// 1-based starting column of the mapping region.
+    start_col: u32,
+
+    /// 1-based ending line of the mapping region.
+    end_line: u32,
+
+    /// 1-based ending column of the mapping region. If the high bit is set, the current
+    /// mapping region is a gap area.
+    end_col: u32,
+
+    kind: RegionKind,
+}
+
+impl CounterMappingRegion {
+    pub(crate) fn code_region(
+        counter: Counter,
+        file_id: u32,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    ) -> Self {
+        Self {
+            counter,
+            false_counter: Counter::zero(),
+            file_id,
+            expanded_file_id: 0,
+            start_line,
+            start_col,
+            end_line,
+            end_col,
+            kind: RegionKind::CodeRegion,
+        }
+    }
+
+    // This function might be used in the future; the LLVM API is still evolving, as is coverage
+    // support.
+    #[allow(dead_code)]
+    pub(crate) fn branch_region(
+        counter: Counter,
+        false_counter: Counter,
+        file_id: u32,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    ) -> Self {
+        Self {
+            counter,
+            false_counter,
+            file_id,
+            expanded_file_id: 0,
+            start_line,
+            start_col,
+            end_line,
+            end_col,
+            kind: RegionKind::BranchRegion,
+        }
+    }
+
+    // This function might be used in the future; the LLVM API is still evolving, as is coverage
+    // support.
+    #[allow(dead_code)]
+    pub(crate) fn expansion_region(
+        file_id: u32,
+        expanded_file_id: u32,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    ) -> Self {
+        Self {
+            counter: Counter::zero(),
+            false_counter: Counter::zero(),
+            file_id,
+            expanded_file_id,
+            start_line,
+            start_col,
+            end_line,
+            end_col,
+            kind: RegionKind::ExpansionRegion,
+        }
+    }
+
+    // This function might be used in the future; the LLVM API is still evolving, as is coverage
+    // support.
+    #[allow(dead_code)]
+    pub(crate) fn skipped_region(
+        file_id: u32,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    ) -> Self {
+        Self {
+            counter: Counter::zero(),
+            false_counter: Counter::zero(),
+            file_id,
+            expanded_file_id: 0,
+            start_line,
+            start_col,
+            end_line,
+            end_col,
+            kind: RegionKind::SkippedRegion,
+        }
+    }
+
+    // This function might be used in the future; the LLVM API is still evolving, as is coverage
+    // support.
+    #[allow(dead_code)]
+    pub(crate) fn gap_region(
+        counter: Counter,
+        file_id: u32,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    ) -> Self {
+        Self {
+            counter,
+            false_counter: Counter::zero(),
+            file_id,
+            expanded_file_id: 0,
+            start_line,
+            start_col,
+            end_line,
+            end_col: (1_u32 << 31) | end_col,
+            kind: RegionKind::GapRegion,
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 7e981af0a53..f1e68af25d4 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -1,4 +1,4 @@
-pub use super::ffi::*;
+use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
 
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::bug;
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 9149b06886b..db9ba0abbde 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,9 +1,8 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
-use crate::coverageinfo::map_data::{Counter, CounterExpression};
+use crate::coverageinfo::ffi::{Counter, CounterExpression, CounterMappingRegion};
 use crate::llvm;
 
-use llvm::coverageinfo::CounterMappingRegion;
 use rustc_codegen_ssa::traits::ConstMethods;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def::DefKind;
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index c1017ab8d7c..afceb7531e6 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -3,10 +3,10 @@ use crate::llvm;
 use crate::abi::Abi;
 use crate::builder::Builder;
 use crate::common::CodegenCx;
-use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage};
+use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
+use crate::coverageinfo::map_data::FunctionCoverage;
 
 use libc::c_uint;
-use llvm::coverageinfo::CounterMappingRegion;
 use rustc_codegen_ssa::traits::{
     BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
     StaticMethods,
@@ -27,7 +27,7 @@ use rustc_middle::ty::Ty;
 use std::cell::RefCell;
 use std::ffi::CString;
 
-mod ffi;
+pub(crate) mod ffi;
 pub(crate) mod map_data;
 pub mod mapgen;
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 40f0bcfdf58..f8cbcbd5ec8 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -990,14 +990,8 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
     closure_or_generator_di_node: &'ll DIType,
 ) -> SmallVec<&'ll DIType> {
     let (&def_id, up_var_tys) = match closure_or_generator_ty.kind() {
-        ty::Generator(def_id, args, _) => {
-            let upvar_tys: SmallVec<_> = args.as_generator().prefix_tys().collect();
-            (def_id, upvar_tys)
-        }
-        ty::Closure(def_id, args) => {
-            let upvar_tys: SmallVec<_> = args.as_closure().upvar_tys().collect();
-            (def_id, upvar_tys)
-        }
+        ty::Generator(def_id, args, _) => (def_id, args.as_generator().prefix_tys()),
+        ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()),
         _ => {
             bug!(
                 "build_upvar_field_di_nodes() called with non-closure-or-generator-type: {:?}",
@@ -1007,9 +1001,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
     };
 
     debug_assert!(
-        up_var_tys
-            .iter()
-            .all(|&t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
+        up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
     );
 
     let capture_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index b4beb80ca8b..d3239d5c358 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -379,6 +379,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>(
             // Fields that are common to all states
             let common_fields: SmallVec<_> = generator_args
                 .prefix_tys()
+                .iter()
                 .zip(common_upvar_names)
                 .enumerate()
                 .map(|(index, (upvar_ty, upvar_name))| {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 7407cfa8c5b..b167facfb02 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1,8 +1,6 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
-use crate::coverageinfo::map_data as coverage_map;
-
 use super::debuginfo::{
     DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
     DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DILocation, DINameSpace,
@@ -688,204 +686,6 @@ extern "C" {
 pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
 pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
 
-pub mod coverageinfo {
-    use super::coverage_map;
-
-    /// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
-    ///
-    /// Must match the layout of `LLVMRustCounterMappingRegionKind`.
-    #[derive(Copy, Clone, Debug)]
-    #[repr(C)]
-    pub enum RegionKind {
-        /// A CodeRegion associates some code with a counter
-        CodeRegion = 0,
-
-        /// An ExpansionRegion represents a file expansion region that associates
-        /// a source range with the expansion of a virtual source file, such as
-        /// for a macro instantiation or #include file.
-        ExpansionRegion = 1,
-
-        /// A SkippedRegion represents a source range with code that was skipped
-        /// by a preprocessor or similar means.
-        SkippedRegion = 2,
-
-        /// A GapRegion is like a CodeRegion, but its count is only set as the
-        /// line execution count when its the only region in the line.
-        GapRegion = 3,
-
-        /// A BranchRegion represents leaf-level boolean expressions and is
-        /// associated with two counters, each representing the number of times the
-        /// expression evaluates to true or false.
-        BranchRegion = 4,
-    }
-
-    /// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
-    /// coverage map, in accordance with the
-    /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
-    /// The struct composes fields representing the `Counter` type and value(s) (injected counter
-    /// ID, or expression type and operands), the source file (an indirect index into a "filenames
-    /// array", encoded separately), and source location (start and end positions of the represented
-    /// code region).
-    ///
-    /// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
-    ///
-    /// Must match the layout of `LLVMRustCounterMappingRegion`.
-    #[derive(Copy, Clone, Debug)]
-    #[repr(C)]
-    pub struct CounterMappingRegion {
-        /// The counter type and type-dependent counter data, if any.
-        counter: coverage_map::Counter,
-
-        /// If the `RegionKind` is a `BranchRegion`, this represents the counter
-        /// for the false branch of the region.
-        false_counter: coverage_map::Counter,
-
-        /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
-        /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
-        /// that, in turn, are used to look up the filename for this region.
-        file_id: u32,
-
-        /// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find
-        /// the mapping regions created as a result of macro expansion, by checking if their file id
-        /// matches the expanded file id.
-        expanded_file_id: u32,
-
-        /// 1-based starting line of the mapping region.
-        start_line: u32,
-
-        /// 1-based starting column of the mapping region.
-        start_col: u32,
-
-        /// 1-based ending line of the mapping region.
-        end_line: u32,
-
-        /// 1-based ending column of the mapping region. If the high bit is set, the current
-        /// mapping region is a gap area.
-        end_col: u32,
-
-        kind: RegionKind,
-    }
-
-    impl CounterMappingRegion {
-        pub(crate) fn code_region(
-            counter: coverage_map::Counter,
-            file_id: u32,
-            start_line: u32,
-            start_col: u32,
-            end_line: u32,
-            end_col: u32,
-        ) -> Self {
-            Self {
-                counter,
-                false_counter: coverage_map::Counter::zero(),
-                file_id,
-                expanded_file_id: 0,
-                start_line,
-                start_col,
-                end_line,
-                end_col,
-                kind: RegionKind::CodeRegion,
-            }
-        }
-
-        // This function might be used in the future; the LLVM API is still evolving, as is coverage
-        // support.
-        #[allow(dead_code)]
-        pub(crate) fn branch_region(
-            counter: coverage_map::Counter,
-            false_counter: coverage_map::Counter,
-            file_id: u32,
-            start_line: u32,
-            start_col: u32,
-            end_line: u32,
-            end_col: u32,
-        ) -> Self {
-            Self {
-                counter,
-                false_counter,
-                file_id,
-                expanded_file_id: 0,
-                start_line,
-                start_col,
-                end_line,
-                end_col,
-                kind: RegionKind::BranchRegion,
-            }
-        }
-
-        // This function might be used in the future; the LLVM API is still evolving, as is coverage
-        // support.
-        #[allow(dead_code)]
-        pub(crate) fn expansion_region(
-            file_id: u32,
-            expanded_file_id: u32,
-            start_line: u32,
-            start_col: u32,
-            end_line: u32,
-            end_col: u32,
-        ) -> Self {
-            Self {
-                counter: coverage_map::Counter::zero(),
-                false_counter: coverage_map::Counter::zero(),
-                file_id,
-                expanded_file_id,
-                start_line,
-                start_col,
-                end_line,
-                end_col,
-                kind: RegionKind::ExpansionRegion,
-            }
-        }
-
-        // This function might be used in the future; the LLVM API is still evolving, as is coverage
-        // support.
-        #[allow(dead_code)]
-        pub(crate) fn skipped_region(
-            file_id: u32,
-            start_line: u32,
-            start_col: u32,
-            end_line: u32,
-            end_col: u32,
-        ) -> Self {
-            Self {
-                counter: coverage_map::Counter::zero(),
-                false_counter: coverage_map::Counter::zero(),
-                file_id,
-                expanded_file_id: 0,
-                start_line,
-                start_col,
-                end_line,
-                end_col,
-                kind: RegionKind::SkippedRegion,
-            }
-        }
-
-        // This function might be used in the future; the LLVM API is still evolving, as is coverage
-        // support.
-        #[allow(dead_code)]
-        pub(crate) fn gap_region(
-            counter: coverage_map::Counter,
-            file_id: u32,
-            start_line: u32,
-            start_col: u32,
-            end_line: u32,
-            end_col: u32,
-        ) -> Self {
-            Self {
-                counter,
-                false_counter: coverage_map::Counter::zero(),
-                file_id,
-                expanded_file_id: 0,
-                start_line,
-                start_col,
-                end_line,
-                end_col: (1_u32 << 31) | end_col,
-                kind: RegionKind::GapRegion,
-            }
-        }
-    }
-}
-
 pub mod debuginfo {
     use super::{InvariantOpaque, Metadata};
     use bitflags::bitflags;
@@ -1911,9 +1711,9 @@ extern "C" {
     pub fn LLVMRustCoverageWriteMappingToBuffer(
         VirtualFileMappingIDs: *const c_uint,
         NumVirtualFileMappingIDs: c_uint,
-        Expressions: *const coverage_map::CounterExpression,
+        Expressions: *const crate::coverageinfo::ffi::CounterExpression,
         NumExpressions: c_uint,
-        MappingRegions: *const coverageinfo::CounterMappingRegion,
+        MappingRegions: *const crate::coverageinfo::ffi::CounterMappingRegion,
         NumMappingRegions: c_uint,
         BufferOut: &RustString,
     );
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 671c2be1de9..2905874eec5 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -282,7 +282,7 @@ const_eval_pointer_out_of_bounds =
         *[many] bytes
     } starting at offset {$ptr_offset} is out-of-bounds
 const_eval_pointer_use_after_free =
-    pointer to {$allocation} was dereferenced after this allocation got freed
+    {$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
 const_eval_ptr_as_bytes_1 =
     this code performed an operation that depends on the underlying bytes representing a pointer
 const_eval_ptr_as_bytes_2 =
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 6630eeca27e..032f4be6c99 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -214,9 +214,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
             // &str or &&str
             assert!(args.len() == 1);
 
-            let mut msg_place = self.deref_operand(&args[0])?;
+            let mut msg_place = self.deref_pointer(&args[0])?;
             while msg_place.layout.ty.is_ref() {
-                msg_place = self.deref_operand(&msg_place)?;
+                msg_place = self.deref_pointer(&msg_place)?;
             }
 
             let msg = Symbol::intern(self.read_str(&msg_place)?);
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 7c1dbddfc26..f785bcfed6c 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -102,7 +102,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
         ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
 
         ty::Ref(_, _, _)  => {
-            let Ok(derefd_place)= ecx.deref_operand(place) else {
+            let Ok(derefd_place)= ecx.deref_pointer(place) else {
                 return Err(ValTreeCreationError::Other);
             };
             debug!(?derefd_place);
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index e1109e584b7..8cbc68d9061 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -492,7 +492,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
             InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
             UnterminatedCString(_) => const_eval_unterminated_c_string,
-            PointerUseAfterFree(_) => const_eval_pointer_use_after_free,
+            PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
             PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
             PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
             DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
@@ -545,8 +545,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
                 builder.set_arg("pointer", ptr);
             }
-            PointerUseAfterFree(allocation) => {
-                builder.set_arg("allocation", allocation);
+            PointerUseAfterFree(alloc_id, msg) => {
+                builder
+                    .set_arg("alloc_id", alloc_id)
+                    .set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
             }
             PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
                 builder
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index be7c14f33c2..29f3e6c724b 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -144,7 +144,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             sym::min_align_of_val | sym::size_of_val => {
-                // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
+                // Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be
                 // dereferenceable!
                 let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
                 let (size, align) = self
@@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_scalar(val, dest)?;
             }
             sym::discriminant_value => {
-                let place = self.deref_operand(&args[0])?;
+                let place = self.deref_pointer(&args[0])?;
                 let variant = self.read_discriminant(&place)?;
                 let discr = self.discriminant_for_variant(place.layout, variant)?;
                 self.write_scalar(discr, dest)?;
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 02d022a2252..940a312d03b 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -317,7 +317,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         kind = "static_mem"
                     )
                 }
-                None => err_ub!(PointerUseAfterFree(alloc_id)),
+                None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
             }
             .into());
         };
@@ -380,7 +380,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             M::enforce_alignment(self),
             CheckInAllocMsg::MemoryAccessTest,
             |alloc_id, offset, prov| {
-                let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
+                let (size, align) = self
+                    .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
                 Ok((size, align, (alloc_id, offset, prov)))
             },
         )
@@ -404,7 +405,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             CheckAlignment::Error,
             msg,
             |alloc_id, _, _| {
-                let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
+                let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
                 Ok((size, align, ()))
             },
         )?;
@@ -414,7 +415,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
     /// to the allocation it points to. Supports both shared and mutable references, as the actual
     /// checking is offloaded to a helper closure. `align` defines whether and which alignment check
-    /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned.
+    /// is done.
+    ///
+    /// If this returns `None`, the size is 0; it can however return `Some` even for size 0.
     fn check_and_deref_ptr<T>(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
@@ -515,7 +518,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)),
             Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
-            None => throw_ub!(PointerUseAfterFree(id)),
+            None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
             Some(GlobalAlloc::Static(def_id)) => {
                 assert!(self.tcx.is_static(def_id));
                 assert!(!self.tcx.is_thread_local_static(def_id));
@@ -761,11 +764,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
-    /// Obtain the size and alignment of a live allocation.
-    pub fn get_live_alloc_size_and_align(&self, id: AllocId) -> InterpResult<'tcx, (Size, Align)> {
+    /// Obtain the size and alignment of a *live* allocation.
+    fn get_live_alloc_size_and_align(
+        &self,
+        id: AllocId,
+        msg: CheckInAllocMsg,
+    ) -> InterpResult<'tcx, (Size, Align)> {
         let (size, align, kind) = self.get_alloc_info(id);
         if matches!(kind, AllocKind::Dead) {
-            throw_ub!(PointerUseAfterFree(id))
+            throw_ub!(PointerUseAfterFree(id, msg))
         }
         Ok((size, align))
     }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 96a960118ce..5f4f5434b18 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -419,7 +419,7 @@ where
     ///
     /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
     /// want to ever use the place for memory access!
-    /// Generally prefer `deref_operand`.
+    /// Generally prefer `deref_pointer`.
     pub fn ref_to_mplace(
         &self,
         val: &ImmTy<'tcx, M::Provenance>,
@@ -439,8 +439,9 @@ where
     }
 
     /// Take an operand, representing a pointer, and dereference it to a place.
+    /// Corresponds to the `*` operator in Rust.
     #[instrument(skip(self), level = "debug")]
-    pub fn deref_operand(
+    pub fn deref_pointer(
         &self,
         src: &impl Readable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index bce43aedb69..539b58b7e9b 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -290,7 +290,7 @@ where
             OpaqueCast(ty) => base.transmute(self.layout_of(ty)?, self)?,
             Field(field, _) => self.project_field(base, field.index())?,
             Downcast(_, variant) => self.project_downcast(base, variant)?,
-            Deref => self.deref_operand(&base.to_op(self)?)?.into(),
+            Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
             Index(local) => {
                 let layout = self.layout_of(self.tcx.types.usize)?;
                 let n = self.local_to_op(self.frame(), local, Some(layout))?;
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index ead172f04a3..0ef5522729a 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -224,8 +224,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             Len(place) => {
                 let src = self.eval_place(place)?;
-                let op = self.place_to_op(&src)?;
-                let len = op.len(self)?;
+                let len = src.len(self)?;
                 self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
             }
 
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index d0191ea978a..bf33c5cca10 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -661,7 +661,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let receiver_place = loop {
                     match receiver.layout.ty.kind() {
                         ty::Ref(..) | ty::RawPtr(..) => {
-                            // We do *not* use `deref_operand` here: we don't want to conceptually
+                            // We do *not* use `deref_pointer` here: we don't want to conceptually
                             // create a place that must be dereferenceable, since the receiver might
                             // be a raw pointer and (for `*const dyn Trait`) we don't need to
                             // actually access memory to resolve this method.
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index aee95f70bc2..ff22d3d2d5a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -345,6 +345,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         value: &OpTy<'tcx, M::Provenance>,
         ptr_kind: PointerKind,
     ) -> InterpResult<'tcx> {
+        // Not using `deref_pointer` since we do the dereferenceable check ourselves below.
         let place = self.ecx.ref_to_mplace(&self.read_immediate(value, ptr_kind.into())?)?;
         // Handle wide pointers.
         // Check metadata early, for better diagnostics
@@ -515,9 +516,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 Ok(true)
             }
             ty::RawPtr(..) => {
-                // We are conservative with uninit for integers, but try to
-                // actually enforce the strict rules for raw pointers (mostly because
-                // that lets us re-use `ref_to_mplace`).
                 let place =
                     self.ecx.ref_to_mplace(&self.read_immediate(value, ExpectedKind::RawPtr)?)?;
                 if place.layout.is_unsized() {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index ad5ffa6511f..b077c10907e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -746,6 +746,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 }
 
                 // Attempting to call a trait method?
+                // FIXME(effects) do we need this?
                 if let Some(trait_id) = tcx.trait_of_item(callee) {
                     trace!("attempting to call a trait method");
                     if !self.tcx.features().const_trait_impl {
@@ -761,7 +762,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     }
 
                     let trait_ref = TraitRef::from_method(tcx, trait_id, fn_args);
-                    let trait_ref = trait_ref.with_constness(ty::BoundConstness::ConstIfConst);
                     let obligation =
                         Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index b152644a551..8293bdfd969 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -155,12 +155,12 @@ impl Qualif for NeedsNonConstDrop {
             return false;
         }
 
+        // FIXME(effects) constness
         let obligation = Obligation::new(
             cx.tcx,
             ObligationCause::dummy_with_span(cx.body.span),
             cx.param_env,
-            ty::TraitRef::from_lang_item(cx.tcx, LangItem::Destruct, cx.body.span, [ty])
-                .with_constness(ty::BoundConstness::ConstIfConst),
+            ty::TraitRef::from_lang_item(cx.tcx, LangItem::Destruct, cx.body.span, [ty]),
         );
 
         let infcx = cx.tcx.infer_ctxt().build();
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 31effadd2c2..83004492c8b 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -630,7 +630,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                     ty::Closure(_, args) => {
                         let args = args.as_closure();
-                        let Some(f_ty) = args.upvar_tys().nth(f.as_usize()) else {
+                        let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else {
                             fail_out_of_bounds(self, location);
                             return;
                         };
@@ -667,7 +667,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
 
                             f_ty.ty
                         } else {
-                            let Some(f_ty) = args.as_generator().prefix_tys().nth(f.index()) else {
+                            let Some(&f_ty) = args.as_generator().prefix_tys().get(f.index())
+                            else {
                                 fail_out_of_bounds(self, location);
                                 return;
                             };
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index bc109e7ad51..b40e3123522 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -713,7 +713,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         );
 
         debug!(?poly_trait_ref, ?assoc_bindings);
-        bounds.push_trait_bound(tcx, poly_trait_ref, span, constness, polarity);
+        bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
 
         let mut dup_bindings = FxHashMap::default();
         for binding in &assoc_bindings {
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index a36ec0c5730..30c2ab8f545 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -62,11 +62,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             match bound_pred.skip_binder() {
                 ty::ClauseKind::Trait(trait_pred) => {
                     assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
-                    trait_bounds.push((
-                        bound_pred.rebind(trait_pred.trait_ref),
-                        span,
-                        trait_pred.constness,
-                    ));
+                    trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
                 }
                 ty::ClauseKind::Projection(proj) => {
                     projection_bounds.push((bound_pred.rebind(proj), span));
@@ -86,7 +82,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // Expand trait aliases recursively and check that only one regular (non-auto) trait
         // is used and no 'maybe' bounds are used.
         let expanded_traits =
-            traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+            traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
 
         let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
             .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
@@ -126,7 +122,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         if regular_traits.is_empty() && auto_traits.is_empty() {
             let trait_alias_span = trait_bounds
                 .iter()
-                .map(|&(trait_ref, _, _)| trait_ref.def_id())
+                .map(|&(trait_ref, _)| trait_ref.def_id())
                 .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
                 .map(|trait_ref| tcx.def_span(trait_ref));
             let reported =
@@ -157,10 +153,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         let regular_traits_refs_spans = trait_bounds
             .into_iter()
-            .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
+            .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
-        for (base_trait_ref, span, constness) in regular_traits_refs_spans {
-            assert_eq!(constness, ty::BoundConstness::NotConst);
+        for (base_trait_ref, span) in regular_traits_refs_spans {
             let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
             for pred in traits::elaborate(tcx, [base_pred]) {
                 debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 531100e1fe6..1d9ae2b9cb7 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -42,13 +42,12 @@ impl<'tcx> Bounds<'tcx> {
         tcx: TyCtxt<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
-        constness: ty::BoundConstness,
         polarity: ty::ImplPolarity,
     ) {
         self.clauses.push((
             trait_ref
                 .map_bound(|trait_ref| {
-                    ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity })
+                    ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
                 })
                 .to_predicate(tcx),
             span,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 6206ba508ae..e64848da86b 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -194,7 +194,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
             // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
             match (tcx.impl_polarity(def_id), impl_.polarity) {
                 (ty::ImplPolarity::Positive, _) => {
-                    check_impl(tcx, item, impl_.self_ty, &impl_.of_trait, impl_.constness);
+                    check_impl(tcx, item, impl_.self_ty, &impl_.of_trait);
                 }
                 (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => {
                     // FIXME(#27579): what amount of WF checking do we need for neg impls?
@@ -1191,7 +1191,6 @@ fn check_impl<'tcx>(
     item: &'tcx hir::Item<'tcx>,
     ast_self_ty: &hir::Ty<'_>,
     ast_trait_ref: &Option<hir::TraitRef<'_>>,
-    constness: hir::Constness,
 ) {
     enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
         match ast_trait_ref {
@@ -1205,14 +1204,8 @@ fn check_impl<'tcx>(
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
                     trait_ref,
                 );
-                let trait_pred = ty::TraitPredicate {
-                    trait_ref,
-                    constness: match constness {
-                        hir::Constness::Const => ty::BoundConstness::ConstIfConst,
-                        hir::Constness::NotConst => ty::BoundConstness::NotConst,
-                    },
-                    polarity: ty::ImplPolarity::Positive,
-                };
+                let trait_pred =
+                    ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive };
                 let mut obligations = traits::wf::trait_obligations(
                     wfcx.infcx,
                     wfcx.param_env,
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index ab3b2dde078..2950ce683a3 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
 /// Returns a list of all type predicates (explicit and implicit) for the definition with
@@ -37,17 +37,10 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
         // from the trait itself that *shouldn't* be shown as the source of
         // an obligation and instead be skipped. Otherwise we'd use
         // `tcx.def_span(def_id);`
-
-        let constness = if tcx.has_attr(def_id, sym::const_trait) {
-            ty::BoundConstness::ConstIfConst
-        } else {
-            ty::BoundConstness::NotConst
-        };
-
         let span = rustc_span::DUMMY_SP;
         result.predicates =
             tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
+                ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
                 span,
             ))));
     }
@@ -204,7 +197,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // (see below). Recall that a default impl is not itself an impl, but rather a
     // set of defaults that can be incorporated into another impl.
     if let Some(trait_ref) = is_default_impl_trait {
-        predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
+        predicates.insert((trait_ref.to_predicate(tcx), tcx.def_span(def_id)));
     }
 
     // Collect the region predicates that were declared inline as
@@ -777,8 +770,7 @@ pub(super) fn type_param_predicates(
                     if param_id == item_hir_id {
                         let identity_trait_ref =
                             ty::TraitRef::identity(tcx, item_def_id.to_def_id());
-                        extend =
-                            Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
+                        extend = Some((identity_trait_ref.to_predicate(tcx), item.span));
                     }
                     generics
                 }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 8b2c93d8fd3..3760195a5e8 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -431,45 +431,13 @@ fn check_predicates<'tcx>(
 ///
 /// So we make that check in this function and try to raise a helpful error message.
 fn trait_predicates_eq<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    _tcx: TyCtxt<'tcx>,
     predicate1: ty::Predicate<'tcx>,
     predicate2: ty::Predicate<'tcx>,
-    span: Span,
+    _span: Span,
 ) -> bool {
-    let pred1_kind = predicate1.kind().skip_binder();
-    let pred2_kind = predicate2.kind().skip_binder();
-    let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) {
-        (
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred1)),
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred2)),
-        ) => (pred1, pred2),
-        // Just use plain syntactic equivalence if either of the predicates aren't
-        // trait predicates or have bound vars.
-        _ => return predicate1 == predicate2,
-    };
-
-    let predicates_equal_modulo_constness = {
-        let pred1_unconsted =
-            ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred1 };
-        let pred2_unconsted =
-            ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred2 };
-        pred1_unconsted == pred2_unconsted
-    };
-
-    if !predicates_equal_modulo_constness {
-        return false;
-    }
-
-    // Check that the predicate on the specializing impl is at least as const as
-    // the one on the base.
-    match (trait_pred2.constness, trait_pred1.constness) {
-        (ty::BoundConstness::ConstIfConst, ty::BoundConstness::NotConst) => {
-            tcx.sess.emit_err(errors::MissingTildeConst { span });
-        }
-        _ => {}
-    }
-
-    true
+    // FIXME(effects)
+    predicate1 == predicate2
 }
 
 #[instrument(level = "debug", skip(tcx))]
@@ -482,7 +450,6 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
         // items.
         ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
             trait_ref,
-            constness: _,
             polarity: _,
         })) => {
             if !matches!(
@@ -536,7 +503,6 @@ fn trait_predicate_kind<'tcx>(
     match predicate.kind().skip_binder() {
         ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
             trait_ref,
-            constness: _,
             polarity: _,
         })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
         ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 1ef257e87d6..6952a3fa66f 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -156,7 +156,6 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
         match pred.kind().skip_binder() {
             ty::ClauseKind::Trait(ty::TraitPredicate {
                 trait_ref: ty::TraitRef { def_id: _, args, .. },
-                constness: _,
                 polarity: _,
             }) => {
                 for subst in &args[1..] {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 8f5737dd4ad..eb6359ed72f 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2988,7 +2988,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ty::Binder::dummy(ty::TraitPredicate {
                             trait_ref: impl_trait_ref,
                             polarity: ty::ImplPolarity::Positive,
-                            constness: ty::BoundConstness::NotConst,
                         }),
                         |derived| {
                             traits::ImplDerivedObligation(Box::new(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index ecafb50f420..1433c67d55d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1461,10 +1461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             param_env,
             bounds,
         ) {
-            // N.B. We are remapping all predicates to non-const since we don't know if we just
-            // want them as function pointers or we are calling them from a const-context. The
-            // actual checking will occur in `rustc_const_eval::transform::check_consts`.
-            self.register_predicate(obligation.without_const(self.tcx));
+            self.register_predicate(obligation);
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index e102c51c7ee..e3d97b41980 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1856,19 +1856,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if self.adjust_fulfillment_error_for_expr_obligation(error)
                 || before_span != error.obligation.cause.span
             {
-                // Store both the predicate and the predicate *without constness*
-                // since sometimes we instantiate and check both of these in a
-                // method call, for example.
                 remap_cause.insert((
                     before_span,
                     error.obligation.predicate,
                     error.obligation.cause.clone(),
                 ));
-                remap_cause.insert((
-                    before_span,
-                    error.obligation.predicate.without_const(self.tcx),
-                    error.obligation.cause.clone(),
-                ));
             } else {
                 // If it failed to be adjusted once around, it may be adjusted
                 // via the "remap cause" mapping the second time...
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 356e7022aea..597696843c4 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -341,15 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
-        (
-            traits::Obligation::new(
-                self.tcx,
-                cause,
-                self.param_env,
-                poly_trait_ref.without_const(),
-            ),
-            args,
-        )
+        (traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args)
     }
 
     /// `lookup_method_in_trait` is used for overloaded operators.
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 05eed1923d1..7164102a30e 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1599,8 +1599,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                             }
                         }
                     }
-                    let predicate =
-                        ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
+                    let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx);
                     parent_pred = Some(predicate);
                     let obligation =
                         traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate);
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index f6c07931023..b9d8c5a7540 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             span,
                             self.body_id,
                             self.param_env,
-                            poly_trait_ref.without_const(),
+                            poly_trait_ref,
                         );
                         self.predicate_may_hold(&obligation)
                     })
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 9c90b704586..a6052f52917 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -448,7 +448,9 @@ where
             ty::Closure(_, ref args) => {
                 // Skip lifetime parameters of the enclosing item(s)
 
-                args.as_closure().tupled_upvars_ty().visit_with(self);
+                for upvar in args.as_closure().upvar_tys() {
+                    upvar.visit_with(self);
+                }
                 args.as_closure().sig_as_fn_ptr_ty().visit_with(self);
             }
 
@@ -456,7 +458,9 @@ where
                 // Skip lifetime parameters of the enclosing item(s)
                 // Also skip the witness type, because that has no free regions.
 
-                args.as_generator().tupled_upvars_ty().visit_with(self);
+                for upvar in args.as_generator().upvar_tys() {
+                    upvar.visit_with(self);
+                }
                 args.as_generator().return_ty().visit_with(self);
                 args.as_generator().yield_ty().visit_with(self);
                 args.as_generator().resume_ty().visit_with(self);
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 11f43469400..64b9714c7c0 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -25,7 +25,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx),
+                predicate: ty::Binder::dummy(trait_ref).to_predicate(infcx.tcx),
             },
         );
     }
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index a9da6104b38..dc41630196b 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -77,13 +77,6 @@ impl<'tcx> PredicateObligation<'tcx> {
             recursion_depth: self.recursion_depth,
         })
     }
-
-    pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> {
-        if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() {
-            self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred.without_const()))));
-        }
-        self
-    }
 }
 
 impl<'tcx> PolyTraitObligation<'tcx> {
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 87ba6b3ec50..93dfbe63bcd 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -264,11 +264,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
                 };
 
                 let obligations =
-                    predicates.predicates.iter().enumerate().map(|(index, &(mut clause, span))| {
-                        // when parent predicate is non-const, elaborate it to non-const predicates.
-                        if data.constness == ty::BoundConstness::NotConst {
-                            clause = clause.without_const(tcx);
-                        }
+                    predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
                         elaboratable.child_with_derived_cause(
                             clause.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
                             span,
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 16e17fc9d6a..f482e3d7c12 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -318,7 +318,11 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir
 
 lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable
 
-lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
+lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+    .label = casting happend here
+
+lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
+    .label = casting happend here
 
 lint_lintpass_by_hand = implementing `LintPass` by hand
     .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 53089294fe2..96fd3ccf774 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -218,7 +218,7 @@ late_lint_methods!(
             BoxPointers: BoxPointers,
             PathStatements: PathStatements,
             LetUnderscore: LetUnderscore,
-            InvalidReferenceCasting: InvalidReferenceCasting,
+            InvalidReferenceCasting: InvalidReferenceCasting::default(),
             // Depends on referenced function signatures in expressions
             UnusedResults: UnusedResults,
             NonUpperCaseGlobals: NonUpperCaseGlobals,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 968172693a9..a6a48bf4ffa 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -745,8 +745,18 @@ pub enum InvalidFromUtf8Diag {
 
 // reference_casting.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_invalid_reference_casting)]
-pub struct InvalidReferenceCastingDiag;
+pub enum InvalidReferenceCastingDiag {
+    #[diag(lint_invalid_reference_casting_borrow_as_mut)]
+    BorrowAsMut {
+        #[label]
+        orig_cast: Option<Span>,
+    },
+    #[diag(lint_invalid_reference_casting_assign_to_ref)]
+    AssignToRef {
+        #[label]
+        orig_cast: Option<Span>,
+    },
+}
 
 // hidden_unicode_codepoints.rs
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index d343aaf35d5..ed3d4721049 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -1,7 +1,8 @@
 use rustc_ast::Mutability;
-use rustc_hir::{Expr, ExprKind, MutTy, TyKind, UnOp};
-use rustc_middle::ty;
-use rustc_span::sym;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, QPath, StmtKind, UnOp};
+use rustc_middle::ty::{self, TypeAndMut};
+use rustc_span::{sym, Span};
 
 use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
 
@@ -12,7 +13,6 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
-    /// # #![deny(invalid_reference_casting)]
     /// fn x(r: &i32) {
     ///     unsafe {
     ///         *(r as *const i32 as *mut i32) += 1;
@@ -30,46 +30,103 @@ declare_lint! {
     /// `UnsafeCell` is the only way to obtain aliasable data that is considered
     /// mutable.
     INVALID_REFERENCE_CASTING,
-    Allow,
+    Deny,
     "casts of `&T` to `&mut T` without interior mutability"
 }
 
-declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
+#[derive(Default)]
+pub struct InvalidReferenceCasting {
+    casted: FxHashMap<HirId, Span>,
+}
+
+impl_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
 
 impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) {
+        let StmtKind::Local(local) = stmt.kind else {
+            return;
+        };
+        let Local { init: Some(init), els: None, .. } = local else {
             return;
         };
 
-        let e = e.peel_blocks();
-        let e = if let ExprKind::Cast(e, t) = e.kind
-            && let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind {
-            e
-        } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
-            && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
-            && cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) {
+        if is_cast_from_const_to_mut(cx, init) {
+            self.casted.insert(local.pat.hir_id, init.span);
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        // &mut <expr>
+        let inner = if let ExprKind::AddrOf(_, Mutability::Mut, expr) = expr.kind {
+            expr
+        // <expr> = ...
+        } else if let ExprKind::Assign(expr, _, _) = expr.kind {
+            expr
+        // <expr> += ...
+        } else if let ExprKind::AssignOp(_, expr, _) = expr.kind {
             expr
         } else {
             return;
         };
 
-        let e = e.peel_blocks();
-        let e = if let ExprKind::Cast(e, t) = e.kind
-            && let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind {
-            e
-        } else if let ExprKind::Call(path, [arg]) = e.kind
-            && let ExprKind::Path(ref qpath) = path.kind
-            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
-            && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
-            arg
+        let ExprKind::Unary(UnOp::Deref, e) = &inner.kind else {
+            return;
+        };
+
+        let orig_cast = if is_cast_from_const_to_mut(cx, e) {
+            None
+        } else if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind
+            && let Res::Local(hir_id) = &path.res
+            && let Some(orig_cast) = self.casted.get(hir_id) {
+            Some(*orig_cast)
         } else {
             return;
         };
 
-        let e = e.peel_blocks();
-        if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind() {
-            cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag);
-        }
+        cx.emit_spanned_lint(
+            INVALID_REFERENCE_CASTING,
+            expr.span,
+            if matches!(expr.kind, ExprKind::AddrOf(..)) {
+                InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
+            } else {
+                InvalidReferenceCastingDiag::AssignToRef { orig_cast }
+            },
+        );
     }
 }
+
+fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
+    let e = e.peel_blocks();
+
+    // <expr> as *mut ...
+    let e = if let ExprKind::Cast(e, t) = e.kind
+        && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
+        e
+    // <expr>.cast_mut()
+    } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
+        && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+        && cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) {
+        expr
+    } else {
+        return false;
+    };
+
+    let e = e.peel_blocks();
+
+    // <expr> as *const ...
+    let e = if let ExprKind::Cast(e, t) = e.kind
+        && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
+        e
+    // ptr::from_ref(<expr>)
+    } else if let ExprKind::Call(path, [arg]) = e.kind
+        && let ExprKind::Path(ref qpath) = path.kind
+        && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+        && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
+        arg
+    } else {
+        return false;
+    };
+
+    let e = e.peel_blocks();
+    matches!(cx.typeck_results().node_type(e.hir_id).kind(), ty::Ref(_, _, Mutability::Not))
+}
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 13b3dac85d1..cc58d51befd 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -25,6 +25,9 @@ metadata_conflicting_alloc_error_handler =
 metadata_conflicting_global_alloc =
     the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
 
+metadata_consider_adding_std =
+    consider adding the standard library to the sysroot with `x build library --target {$locator_triple}`
+
 metadata_consider_building_std =
     consider building the standard library from source with `cargo build -Zbuild-std`
 
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index fca06c0f47c..91220629fb6 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -623,6 +623,7 @@ pub struct CannotFindCrate {
     pub is_nightly_build: bool,
     pub profiler_runtime: Symbol,
     pub locator_triple: TargetTriple,
+    pub is_ui_testing: bool,
 }
 
 impl IntoDiagnostic<'_> for CannotFindCrate {
@@ -646,12 +647,19 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
             } else {
                 diag.note(fluent::metadata_target_no_std_support);
             }
-            // NOTE: this suggests using rustup, even though the user may not have it installed.
-            // That's because they could choose to install it; or this may give them a hint which
-            // target they need to install from their distro.
+
             if self.missing_core {
-                diag.help(fluent::metadata_consider_downloading_target);
+                if env!("CFG_RELEASE_CHANNEL") == "dev" && !self.is_ui_testing {
+                    // Note: Emits the nicer suggestion only for the dev channel.
+                    diag.help(fluent::metadata_consider_adding_std);
+                } else {
+                    // NOTE: this suggests using rustup, even though the user may not have it installed.
+                    // That's because they could choose to install it; or this may give them a hint which
+                    // target they need to install from their distro.
+                    diag.help(fluent::metadata_consider_downloading_target);
+                }
             }
+
             // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
             // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
             // If it's not a dummy, that means someone added `extern crate std` explicitly and
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index fb9dd660d2f..a0c552f5fd6 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -1130,6 +1130,7 @@ impl CrateError {
                         is_nightly_build: sess.is_nightly_build(),
                         profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
                         locator_triple: locator.triple,
+                        is_ui_testing: sess.opts.unstable_opts.ui_testing,
                     });
                 }
             }
@@ -1146,6 +1147,7 @@ impl CrateError {
                     is_nightly_build: sess.is_nightly_build(),
                     profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
                     locator_triple: sess.opts.target_triple.clone(),
+                    is_ui_testing: sess.opts.unstable_opts.ui_testing,
                 });
             }
         }
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index d44dfa2172a..eaa6c0ce2d6 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -282,8 +282,8 @@ pub enum UndefinedBehaviorInfo<'a> {
     InvalidMeta(InvalidMetaKind),
     /// Reading a C string that does not end within its allocation.
     UnterminatedCString(Pointer),
-    /// Dereferencing a dangling pointer after it got freed.
-    PointerUseAfterFree(AllocId),
+    /// Using a pointer after it got freed.
+    PointerUseAfterFree(AllocId, CheckInAllocMsg),
     /// Used a pointer outside the bounds it is valid for.
     /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
     PointerOutOfBounds {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 0f7bed0845c..df39103bc19 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -911,7 +911,7 @@ where
                         if i == tag_field {
                             return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
                         }
-                        TyMaybeWithLayout::Ty(args.as_generator().prefix_tys().nth(i).unwrap())
+                        TyMaybeWithLayout::Ty(args.as_generator().prefix_tys()[i])
                     }
                 },
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 2b4c834f766..6b0f0132062 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -498,11 +498,9 @@ impl<'tcx> Predicate<'tcx> {
             .map_bound(|kind| match kind {
                 PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
                     trait_ref,
-                    constness,
                     polarity,
                 })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
                     trait_ref,
-                    constness,
                     polarity: polarity.flip()?,
                 }))),
 
@@ -513,19 +511,6 @@ impl<'tcx> Predicate<'tcx> {
         Some(tcx.mk_predicate(kind))
     }
 
-    pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self {
-        if let PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder()
-            && constness != BoundConstness::NotConst
-        {
-            self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
-                trait_ref,
-                constness: BoundConstness::NotConst,
-                polarity,
-            }))));
-        }
-        self
-    }
-
     #[instrument(level = "debug", skip(tcx), ret)]
     pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind().skip_binder() {
@@ -629,10 +614,6 @@ impl<'tcx> Clause<'tcx> {
             None
         }
     }
-
-    pub fn without_const(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        self.as_predicate().without_const(tcx).expect_clause()
-    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
@@ -852,8 +833,6 @@ impl<'tcx> Clause<'tcx> {
 pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>,
 
-    pub constness: BoundConstness,
-
     /// If polarity is Positive: we are proving that the trait is implemented.
     ///
     /// If polarity is Negative: we are proving that a negative impl of this trait
@@ -878,24 +857,6 @@ impl<'tcx> TraitPredicate<'tcx> {
     pub fn self_ty(self) -> Ty<'tcx> {
         self.trait_ref.self_ty()
     }
-
-    #[inline]
-    pub fn is_const_if_const(self) -> bool {
-        self.constness == BoundConstness::ConstIfConst
-    }
-
-    pub fn is_constness_satisfied_by(self, constness: hir::Constness) -> bool {
-        match (self.constness, constness) {
-            (BoundConstness::NotConst, _)
-            | (BoundConstness::ConstIfConst, hir::Constness::Const) => true,
-            (BoundConstness::ConstIfConst, hir::Constness::NotConst) => false,
-        }
-    }
-
-    pub fn without_const(mut self) -> Self {
-        self.constness = BoundConstness::NotConst;
-        self
-    }
 }
 
 impl<'tcx> PolyTraitPredicate<'tcx> {
@@ -909,11 +870,6 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
     }
 
     #[inline]
-    pub fn is_const_if_const(self) -> bool {
-        self.skip_binder().is_const_if_const()
-    }
-
-    #[inline]
     pub fn polarity(self) -> ImplPolarity {
         self.skip_binder().polarity
     }
@@ -1287,7 +1243,7 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
 impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> {
     #[inline(always)]
     fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> {
-        self.without_const()
+        TraitPredicate { trait_ref: self, polarity: ImplPolarity::Positive }
     }
 }
 
@@ -1328,7 +1284,6 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef
     fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
         self.map_bound(|trait_ref| TraitPredicate {
             trait_ref,
-            constness: ty::BoundConstness::NotConst,
             polarity: ty::ImplPolarity::Positive,
         })
     }
@@ -1826,24 +1781,6 @@ impl<'tcx> ParamEnv<'tcx> {
     }
 }
 
-// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
-// the constness of trait bounds is being propagated correctly.
-impl<'tcx> PolyTraitRef<'tcx> {
-    #[inline]
-    pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> {
-        self.map_bound(|trait_ref| ty::TraitPredicate {
-            trait_ref,
-            constness,
-            polarity: ty::ImplPolarity::Positive,
-        })
-    }
-
-    #[inline]
-    pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
-        self.with_constness(BoundConstness::NotConst)
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
 #[derive(HashStable, Lift)]
 pub struct ParamEnvAnd<'tcx, T> {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index f146f8aa8b4..6e68022031a 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -827,7 +827,7 @@ pub trait PrettyPrinter<'tcx>:
                     if !args.as_generator().is_valid() {
                         p!("unavailable");
                     } else {
-                        self = self.comma_sep(args.as_generator().upvar_tys())?;
+                        self = self.comma_sep(args.as_generator().upvar_tys().iter())?;
                     }
                     p!(")");
 
@@ -900,7 +900,7 @@ pub trait PrettyPrinter<'tcx>:
                             print(args.as_closure().sig_as_fn_ptr_ty())
                         );
                         p!(" upvar_tys=(");
-                        self = self.comma_sep(args.as_closure().upvar_tys())?;
+                        self = self.comma_sep(args.as_closure().upvar_tys().iter())?;
                         p!(")");
                     }
                 }
@@ -2806,10 +2806,7 @@ define_print_and_forward_display! {
     }
 
     TraitPredPrintModifiersAndPath<'tcx> {
-        if let ty::BoundConstness::ConstIfConst = self.0.constness {
-            p!("~const ")
-        }
-
+        // FIXME(effects) print `~const` here
         if let ty::ImplPolarity::Negative = self.0.polarity {
             p!("!")
         }
@@ -2843,9 +2840,7 @@ define_print_and_forward_display! {
 
     ty::TraitPredicate<'tcx> {
         p!(print(self.trait_ref.self_ty()), ": ");
-        if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
-            p!("~const ");
-        }
+        // FIXME(effects) print `~const` here
         if let ty::ImplPolarity::Negative = self.polarity {
             p!("!");
         }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index bf9adabdab1..47512d350e5 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -826,7 +826,6 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
     ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> {
         Ok(ty::TraitPredicate {
             trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
-            constness: relation.relate(a.constness, b.constness)?,
             polarity: relation.relate(a.polarity, b.polarity)?,
         })
     }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index c6b6f0e8990..1347b35556d 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -172,9 +172,7 @@ impl fmt::Debug for ty::ParamConst {
 
 impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let ty::BoundConstness::ConstIfConst = self.constness {
-            write!(f, "~const ")?;
-        }
+        // FIXME(effects) printing?
         write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 3e023ccdead..a695febf087 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -296,15 +296,13 @@ impl<'tcx> ClosureArgs<'tcx> {
     /// In case there was a type error in figuring out the types of the captured path, an
     /// empty iterator is returned.
     #[inline]
-    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+    pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
         match self.tupled_upvars_ty().kind() {
-            TyKind::Error(_) => None,
-            TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
+            TyKind::Error(_) => ty::List::empty(),
+            TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
             TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
             ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
         }
-        .into_iter()
-        .flatten()
     }
 
     /// Returns the tuple type representing the upvars for this closure.
@@ -436,15 +434,13 @@ impl<'tcx> GeneratorArgs<'tcx> {
     /// In case there was a type error in figuring out the types of the captured path, an
     /// empty iterator is returned.
     #[inline]
-    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+    pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
         match self.tupled_upvars_ty().kind() {
-            TyKind::Error(_) => None,
-            TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
+            TyKind::Error(_) => ty::List::empty(),
+            TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
             TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
             ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
         }
-        .into_iter()
-        .flatten()
     }
 
     /// Returns the tuple type representing the upvars for this generator.
@@ -576,7 +572,7 @@ impl<'tcx> GeneratorArgs<'tcx> {
     /// This is the types of the fields of a generator which are not stored in a
     /// variant.
     #[inline]
-    pub fn prefix_tys(self) -> impl Iterator<Item = Ty<'tcx>> {
+    pub fn prefix_tys(self) -> &'tcx List<Ty<'tcx>> {
         self.upvar_tys()
     }
 }
@@ -592,20 +588,18 @@ impl<'tcx> UpvarArgs<'tcx> {
     /// In case there was a type error in figuring out the types of the captured path, an
     /// empty iterator is returned.
     #[inline]
-    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+    pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
         let tupled_tys = match self {
             UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(),
             UpvarArgs::Generator(args) => args.as_generator().tupled_upvars_ty(),
         };
 
         match tupled_tys.kind() {
-            TyKind::Error(_) => None,
-            TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
+            TyKind::Error(_) => ty::List::empty(),
+            TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
             TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
             ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
         }
-        .into_iter()
-        .flatten()
     }
 
     #[inline]
@@ -728,7 +722,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
         use crate::ty::ToPredicate;
         match self.skip_binder() {
             ExistentialPredicate::Trait(tr) => {
-                self.rebind(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx)
+                self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx)
             }
             ExistentialPredicate::Projection(p) => {
                 self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
@@ -743,7 +737,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
                     let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
                     ty::TraitRef::new(tcx, did, err_args)
                 };
-                self.rebind(trait_ref).without_const().to_predicate(tcx)
+                self.rebind(trait_ref).to_predicate(tcx)
             }
         }
     }
@@ -875,18 +869,6 @@ impl<'tcx> TraitRef<'tcx> {
         )
     }
 
-    /// Converts this trait ref to a trait predicate with a given `constness` and a positive polarity.
-    #[inline]
-    pub fn with_constness(self, constness: ty::BoundConstness) -> ty::TraitPredicate<'tcx> {
-        ty::TraitPredicate { trait_ref: self, constness, polarity: ty::ImplPolarity::Positive }
-    }
-
-    /// Converts this trait ref to a trait predicate without `const` and a positive polarity.
-    #[inline]
-    pub fn without_const(self) -> ty::TraitPredicate<'tcx> {
-        self.with_constness(ty::BoundConstness::NotConst)
-    }
-
     #[inline]
     pub fn self_ty(&self) -> Ty<'tcx> {
         self.args.type_at(0)
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 1d7d905c937..9e02b027182 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -860,20 +860,14 @@ where
     fn open_drop(&mut self) -> BasicBlock {
         let ty = self.place_ty(self.place);
         match ty.kind() {
-            ty::Closure(_, args) => {
-                let tys: Vec<_> = args.as_closure().upvar_tys().collect();
-                self.open_drop_for_tuple(&tys)
-            }
+            ty::Closure(_, args) => self.open_drop_for_tuple(&args.as_closure().upvar_tys()),
             // Note that `elaborate_drops` only drops the upvars of a generator,
             // and this is ok because `open_drop` here can only be reached
             // within that own generator's resume function.
             // This should only happen for the self argument on the resume function.
             // It effectively only contains upvars until the generator transformation runs.
             // See librustc_body/transform/generator.rs for more details.
-            ty::Generator(_, args, _) => {
-                let tys: Vec<_> = args.as_generator().upvar_tys().collect();
-                self.open_drop_for_tuple(&tys)
-            }
+            ty::Generator(_, args, _) => self.open_drop_for_tuple(&args.as_generator().upvar_tys()),
             ty::Tuple(fields) => self.open_drop_for_tuple(fields),
             ty::Adt(def, args) => self.open_drop_for_adt(*def, args),
             ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 669135f80bc..797a1a86846 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -856,7 +856,7 @@ fn sanitize_witness<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     witness: Ty<'tcx>,
-    upvars: Vec<Ty<'tcx>>,
+    upvars: &'tcx ty::List<Ty<'tcx>>,
     layout: &GeneratorLayout<'tcx>,
 ) {
     let did = body.source.def_id();
@@ -1471,7 +1471,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
                 let args = args.as_generator();
                 (
                     args.discr_ty(tcx),
-                    args.upvar_tys().collect::<Vec<_>>(),
+                    args.upvar_tys(),
                     args.witness(),
                     movability == hir::Movability::Movable,
                 )
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 5fa780a372b..af9efb82beb 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -147,7 +147,7 @@ where
 
     fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> ControlFlow<V::BreakTy> {
         match clause.kind().skip_binder() {
-            ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
+            ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
                 self.visit_trait(trait_ref)
             }
             ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 6efc1e7302c..38153cccfdd 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -72,7 +72,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             cause: traits::ObligationCause::dummy(),
             param_env,
             recursion_depth: 0,
-            predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
+            predicate: ty::Binder::dummy(trait_ref).to_predicate(self.tcx),
         };
         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 5ec48c7ac57..8bf003f863e 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -727,7 +727,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                     self.tcx(),
                     ty::TraitPredicate {
                         trait_ref: self_trait_ref,
-                        constness: ty::BoundConstness::NotConst,
                         polarity: ty::ImplPolarity::Positive,
                     },
                 );
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 94d3cd035aa..ba5000da6cd 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -97,7 +97,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 orig_env,
                 ty::TraitPredicate {
                     trait_ref,
-                    constness: ty::BoundConstness::NotConst,
                     polarity: if polarity {
                         ImplPolarity::Positive
                     } else {
@@ -260,7 +259,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         predicates.push_back(ty::Binder::dummy(ty::TraitPredicate {
             trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]),
 
-            constness: ty::BoundConstness::NotConst,
             // Auto traits are positive
             polarity: ty::ImplPolarity::Positive,
         }));
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 61f693e1bd1..820973dc090 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -97,7 +97,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
             cause,
             recursion_depth: 0,
             param_env,
-            predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+            predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
         });
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 95485850d0e..eae13eb6302 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -100,7 +100,6 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         param_env: ty::ParamEnv<'tcx>,
         ty: ty::Binder<'tcx, Ty<'tcx>>,
-        constness: ty::BoundConstness,
         polarity: ty::ImplPolarity,
     ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
 }
@@ -356,7 +355,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         &self,
         param_env: ty::ParamEnv<'tcx>,
         ty: ty::Binder<'tcx, Ty<'tcx>>,
-        constness: ty::BoundConstness,
         polarity: ty::ImplPolarity,
     ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
         self.commit_if_ok(|_| {
@@ -372,12 +370,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                     span: DUMMY_SP,
                     kind: TypeVariableOriginKind::MiscVariable,
                 });
+                // FIXME(effects)
                 let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
                 let obligation = Obligation::new(
                     self.tcx,
                     ObligationCause::dummy(),
                     param_env,
-                    ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }),
+                    ty.rebind(ty::TraitPredicate { trait_ref, polarity }),
                 );
                 let ocx = ObligationCtxt::new(self);
                 ocx.register_obligation(obligation);
@@ -689,8 +688,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         let trait_predicate = bound_predicate.rebind(trait_predicate);
                         let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
 
-                        let predicate_is_const = ty::BoundConstness::ConstIfConst
-                            == trait_predicate.skip_binder().constness;
+                        // FIXME(effects)
+                        let predicate_is_const = false;
 
                         if self.tcx.sess.has_errors().is_some()
                             && trait_predicate.references_error()
@@ -1909,9 +1908,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             .all_impls(trait_pred.def_id())
             .filter_map(|def_id| {
                 if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
-                    || !trait_pred
-                        .skip_binder()
-                        .is_constness_satisfied_by(self.tcx.constness(def_id))
                     || !self.tcx.is_user_visible_dep(def_id.krate)
                 {
                     return None;
@@ -2996,7 +2992,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
             obligation.param_env,
             trait_ref.self_ty(),
-            trait_predicate.skip_binder().constness,
             trait_predicate.skip_binder().polarity,
         )
         {
@@ -3099,14 +3094,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
     fn maybe_add_note_for_unsatisfied_const(
         &self,
-        obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
-        err: &mut Diagnostic,
-        span: Span,
+        _obligation: &PredicateObligation<'tcx>,
+        _trait_ref: ty::PolyTraitRef<'tcx>,
+        _trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        _err: &mut Diagnostic,
+        _span: Span,
     ) -> UnsatisfiedConst {
-        let mut unsatisfied_const = UnsatisfiedConst(false);
-        if trait_predicate.is_const_if_const() {
+        let unsatisfied_const = UnsatisfiedConst(false);
+        // FIXME(effects)
+        /* if trait_predicate.is_const_if_const() {
             let non_const_predicate = trait_ref.without_const();
             let non_const_obligation = Obligation {
                 cause: obligation.cause.clone(),
@@ -3126,7 +3122,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     ),
                 );
             }
-        }
+        } */
         unsatisfied_const
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 593f669e9bb..d2210c6d5d9 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -133,7 +133,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
     def_id: DefId,
 ) -> bool {
     let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
-    pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const())
+    pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref)
 }
 
 /// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 76752edc4ae..5823b4508d9 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -574,7 +574,6 @@ fn virtual_call_violation_for_method<'tcx>(
         // implement auto traits if the underlying type does as well.
         if let ty::ClauseKind::Trait(ty::TraitPredicate {
             trait_ref: pred_trait_ref,
-            constness: ty::BoundConstness::NotConst,
             polarity: ty::ImplPolarity::Positive,
         }) = pred.kind().skip_binder()
             && pred_trait_ref.self_ty() == tcx.types.self_param
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 98f45826727..3d800421b76 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1306,7 +1306,7 @@ fn normalize_to_error<'a, 'tcx>(
         cause,
         recursion_depth: depth,
         param_env,
-        predicate: trait_ref.without_const().to_predicate(selcx.tcx()),
+        predicate: trait_ref.to_predicate(selcx.tcx()),
     };
     let tcx = selcx.infcx.tcx;
     let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin {
@@ -1867,8 +1867,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                             if selcx.infcx.predicate_must_hold_modulo_regions(
                                 &obligation.with(
                                     selcx.tcx(),
-                                    ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty])
-                                        .without_const(),
+                                    ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]),
                                 ),
                             ) =>
                         {
@@ -2152,8 +2151,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
                 LangItem::Sized,
                 obligation.cause.span(),
                 [self_ty],
-            )
-            .without_const();
+            );
             obligations.push(obligation.with(tcx, sized_predicate));
         }
         (metadata_ty.into(), obligations)
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 ef989d8c9d6..9484a50e3a9 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -291,9 +291,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
                 return Err(NoSolution);
             }
 
-            constraints.outlives.extend(
-                args.as_generator().upvar_tys().map(|t| -> ty::GenericArg<'tcx> { t.into() }),
-            );
+            constraints
+                .outlives
+                .extend(args.as_generator().upvar_tys().iter().map(ty::GenericArg::from));
             constraints.outlives.push(args.as_generator().resume_ty().into());
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index b9f31be25b1..8f2f02a5e41 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -154,9 +154,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .infcx
             .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
 
-        candidates
-            .vec
-            .extend(result.into_iter().map(|(idx, constness)| ProjectionCandidate(idx, constness)));
+        // FIXME(effects) proper constness needed?
+        candidates.vec.extend(
+            result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)),
+        );
     }
 
     /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 7140fedb74a..bf09681c66d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -59,7 +59,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ParamCandidate(param) => {
                 let obligations =
                     self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
-                ImplSource::Param(param.skip_binder().constness, obligations)
+                // FIXME(effects)
+                ImplSource::Param(ty::BoundConstness::NotConst, obligations)
             }
 
             ImplCandidate(impl_def_id) => {
@@ -128,14 +129,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             subobligation.set_depth_from_parent(obligation.recursion_depth);
         }
 
-        if !obligation.predicate.is_const_if_const() {
-            // normalize nested predicates according to parent predicate's constness.
-            impl_src = impl_src.map(|mut o| {
-                o.predicate = o.predicate.without_const(self.tcx());
-                o
-            });
-        }
-
         Ok(impl_src)
     }
 
@@ -1305,6 +1298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // If we have a projection type, make sure to normalize it so we replace it
                 // with a fresh infer variable
                 ty::Alias(ty::Projection | ty::Inherent, ..) => {
+                    // FIXME(effects) this needs constness
                     let predicate = normalize_with_depth_to(
                         self,
                         obligation.param_env,
@@ -1317,7 +1311,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 cause.span,
                                 [nested_ty],
                             ),
-                            constness: ty::BoundConstness::ConstIfConst,
                             polarity: ty::ImplPolarity::Positive,
                         }),
                         &mut nested,
@@ -1336,6 +1329,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // since it's either not `const Drop` (and we raise an error during selection),
                 // or it's an ADT (and we need to check for a custom impl during selection)
                 _ => {
+                    // FIXME(effects) this needs constness
                     let predicate = self_ty.rebind(ty::TraitPredicate {
                         trait_ref: ty::TraitRef::from_lang_item(
                             self.tcx(),
@@ -1343,7 +1337,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             cause.span,
                             [nested_ty],
                         ),
-                        constness: ty::BoundConstness::ConstIfConst,
                         polarity: ty::ImplPolarity::Positive,
                     });
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 6080a440de6..5da8d838db2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1583,7 +1583,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> {
+    ) -> smallvec::SmallVec<[usize; 2]> {
         let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
         let placeholder_trait_predicate =
             self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
@@ -1632,7 +1632,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             _ => false,
                         }
                     }) {
-                        return Some((idx, pred.constness));
+                        return Some(idx);
                     }
                 }
                 None
@@ -1820,7 +1820,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             (ParamCandidate(other), ParamCandidate(victim)) => {
                 let same_except_bound_vars = other.skip_binder().trait_ref
                     == victim.skip_binder().trait_ref
-                    && other.skip_binder().constness == victim.skip_binder().constness
                     && other.skip_binder().polarity == victim.skip_binder().polarity
                     && !other.skip_binder().trait_ref.has_escaping_bound_vars();
                 if same_except_bound_vars {
@@ -1830,12 +1829,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     // probably best characterized as a "hack", since we might prefer to just do our
                     // best to *not* create essentially duplicate candidates in the first place.
                     DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len())
-                } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
-                    && victim.skip_binder().constness == ty::BoundConstness::NotConst
-                    && other.skip_binder().polarity == victim.skip_binder().polarity
-                {
-                    // Drop otherwise equivalent non-const candidates in favor of const candidates.
-                    DropVictim::Yes
                 } else {
                     DropVictim::No
                 }
@@ -2169,7 +2162,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                         let all = args
                             .as_generator()
                             .upvar_tys()
-                            .chain(iter::once(args.as_generator().witness()))
+                            .iter()
+                            .chain([args.as_generator().witness()])
                             .collect::<Vec<_>>();
                         Where(obligation.predicate.rebind(all))
                     }
@@ -2210,7 +2204,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     // Not yet resolved.
                     Ambiguous
                 } else {
-                    Where(obligation.predicate.rebind(args.as_closure().upvar_tys().collect()))
+                    Where(obligation.predicate.rebind(args.as_closure().upvar_tys().to_vec()))
                 }
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 61e631c438d..729cf2f3313 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -500,16 +500,12 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
     let mut pretty_predicates =
         Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
 
-    for (mut p, _) in predicates {
+    for (p, _) in predicates {
         if let Some(poly_trait_ref) = p.as_trait_clause() {
             if Some(poly_trait_ref.def_id()) == sized_trait {
                 types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder());
                 continue;
             }
-
-            if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness {
-                p = p.without_const(tcx);
-            }
         }
         pretty_predicates.push(p.to_string());
     }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 4c27fe8b29b..a76272e9d09 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -101,7 +101,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
     fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
         let tcx = self.tcx;
         let trait_ref = item.trait_ref();
-        let pred = trait_ref.without_const().to_predicate(tcx);
+        let pred = trait_ref.to_predicate(tcx);
 
         debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
 
@@ -113,9 +113,13 @@ impl<'tcx> TraitAliasExpander<'tcx> {
 
         // Don't recurse if this trait alias is already on the stack for the DFS search.
         let anon_pred = anonymize_predicate(tcx, pred);
-        if item.path.iter().rev().skip(1).any(|&(tr, _)| {
-            anonymize_predicate(tcx, tr.without_const().to_predicate(tcx)) == anon_pred
-        }) {
+        if item
+            .path
+            .iter()
+            .rev()
+            .skip(1)
+            .any(|&(tr, _)| anonymize_predicate(tcx, tr.to_predicate(tcx)) == anon_pred)
+        {
             return false;
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 3964dda1fdb..427ac368432 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -86,7 +86,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
 
     let mut emit_vptr_on_new_entry = false;
     let mut visited = PredicateSet::new(tcx);
-    let predicate = trait_ref.without_const().to_predicate(tcx);
+    let predicate = trait_ref.to_predicate(tcx);
     let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
         smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))];
     visited.insert(predicate);
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 5f6bb04fda4..f26310665f9 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -348,11 +348,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         }
 
         // if the trait predicate is not const, the wf obligations should not be const as well.
-        let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
-            self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.args)
-        } else {
-            self.nominal_obligations(trait_ref.def_id, trait_ref.args)
-        };
+        let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.args);
 
         debug!("compute_trait_pred obligations {:?}", obligations);
         let param_env = self.param_env;
@@ -445,8 +441,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         //     `i32: Clone`
         //     `i32: Copy`
         // ]
-        // Projection types do not require const predicates.
-        let obligations = self.nominal_obligations_without_const(data.def_id, data.args);
+        let obligations = self.nominal_obligations(data.def_id, data.args);
         self.out.extend(obligations);
 
         self.compute_projection_args(data.args);
@@ -472,8 +467,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 self.recursion_depth,
                 &mut self.out,
             );
-            // Inherent projection types do not require const predicates.
-            let obligations = self.nominal_obligations_without_const(data.def_id, args);
+            let obligations = self.nominal_obligations(data.def_id, args);
             self.out.extend(obligations);
         }
 
@@ -516,7 +510,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 cause,
                 self.recursion_depth,
                 self.param_env,
-                ty::Binder::dummy(trait_ref).without_const(),
+                ty::Binder::dummy(trait_ref),
             ));
         }
     }
@@ -667,7 +661,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 }
 
                 ty::FnDef(did, args) => {
-                    let obligations = self.nominal_obligations_without_const(did, args);
+                    let obligations = self.nominal_obligations(did, args);
                     self.out.extend(obligations);
                 }
 
@@ -822,11 +816,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn nominal_obligations_inner(
+    fn nominal_obligations(
         &mut self,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
-        remap_constness: bool,
     ) -> Vec<traits::PredicateObligation<'tcx>> {
         let predicates = self.tcx().predicates_of(def_id);
         let mut origins = vec![def_id; predicates.predicates.len()];
@@ -841,16 +834,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         debug_assert_eq!(predicates.predicates.len(), origins.len());
 
         iter::zip(predicates, origins.into_iter().rev())
-            .map(|((mut pred, span), origin_def_id)| {
+            .map(|((pred, span), origin_def_id)| {
                 let code = if span.is_dummy() {
                     traits::ItemObligation(origin_def_id)
                 } else {
                     traits::BindingObligation(origin_def_id, span)
                 };
                 let cause = self.cause(code);
-                if remap_constness {
-                    pred = pred.without_const(self.tcx());
-                }
                 traits::Obligation::with_depth(
                     self.tcx(),
                     cause,
@@ -863,22 +853,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
             .collect()
     }
 
-    fn nominal_obligations(
-        &mut self,
-        def_id: DefId,
-        args: GenericArgsRef<'tcx>,
-    ) -> Vec<traits::PredicateObligation<'tcx>> {
-        self.nominal_obligations_inner(def_id, args, false)
-    }
-
-    fn nominal_obligations_without_const(
-        &mut self,
-        def_id: DefId,
-        args: GenericArgsRef<'tcx>,
-    ) -> Vec<traits::PredicateObligation<'tcx>> {
-        self.nominal_obligations_inner(def_id, args, true)
-    }
-
     fn from_object_ty(
         &mut self,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 3500c2cc370..6b4273c03e4 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -317,7 +317,9 @@ fn layout_of_uncached<'tcx>(
         ty::Closure(_, ref args) => {
             let tys = args.as_closure().upvar_tys();
             univariant(
-                &tys.map(|ty| Ok(cx.layout_of(ty)?.layout)).try_collect::<IndexVec<_, _>>()?,
+                &tys.iter()
+                    .map(|ty| Ok(cx.layout_of(ty)?.layout))
+                    .try_collect::<IndexVec<_, _>>()?,
                 &ReprOptions::default(),
                 StructKind::AlwaysSized,
             )?
@@ -729,7 +731,7 @@ fn generator_layout<'tcx>(
     // Build a prefix layout, including "promoting" all ineligible
     // locals as part of the prefix. We compute the layout of all of
     // these fields at once to get optimal packing.
-    let tag_index = args.as_generator().prefix_tys().count();
+    let tag_index = args.as_generator().prefix_tys().len();
 
     // `info.variant_fields` already accounts for the reserved variants, so no need to add them.
     let max_discr = (info.variant_fields.len() - 1) as u128;
@@ -748,6 +750,7 @@ fn generator_layout<'tcx>(
     let prefix_layouts = args
         .as_generator()
         .prefix_tys()
+        .iter()
         .map(|ty| Ok(cx.layout_of(ty)?.layout))
         .chain(iter::once(Ok(tag_layout)))
         .chain(promoted_layouts)
@@ -1062,6 +1065,7 @@ fn variant_info_for_generator<'tcx>(
     let upvar_fields: Vec<_> = args
         .as_generator()
         .upvar_tys()
+        .iter()
         .zip(upvar_names)
         .enumerate()
         .map(|(field_idx, (_, name))| {
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index f89558a4599..34fd31e49e1 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -120,12 +120,16 @@ where
                     _ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
 
                     ty::Closure(_, args) => {
-                        queue_type(self, args.as_closure().tupled_upvars_ty());
+                        for upvar in args.as_closure().upvar_tys() {
+                            queue_type(self, upvar);
+                        }
                     }
 
                     ty::Generator(def_id, args, _) => {
                         let args = args.as_generator();
-                        queue_type(self, args.tupled_upvars_ty());
+                        for upvar in args.upvar_tys() {
+                            queue_type(self, upvar);
+                        }
 
                         let witness = args.witness();
                         let interior_tys = match witness.kind() {
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 909b32547e7..bf4c682d33e 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1893,7 +1893,8 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 /// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
 /// same memory layout, the following is not allowed and undefined behavior:
 ///
-/// ```rust,no_run
+#[cfg_attr(bootstrap, doc = "```rust,no_run")]
+#[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")]
 /// # use std::cell::UnsafeCell;
 /// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
 ///   let t = ptr as *const UnsafeCell<T> as *mut T;
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 549fec9477a..b59ec12790d 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -197,8 +197,8 @@ impl CStr {
     ///
     /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
     /// allows inspection and interoperation of non-owned C strings. The total
-    /// size of the raw C string must be smaller than `isize::MAX` **bytes**
-    /// in memory due to calling the `slice::from_raw_parts` function.
+    /// size of the terminated buffer must be smaller than [`isize::MAX`] **bytes**
+    /// in memory (a restriction from [`slice::from_raw_parts`]).
     ///
     /// # Safety
     ///
@@ -295,11 +295,11 @@ impl CStr {
         }
     }
 
-    /// Creates a C string wrapper from a byte slice.
+    /// Creates a C string wrapper from a byte slice with any number of nuls.
     ///
     /// This method will create a `CStr` from any byte slice that contains at
-    /// least one nul byte. The caller does not need to know or specify where
-    /// the nul byte is located.
+    /// least one nul byte. Unlike with [`CStr::from_bytes_with_nul`], the caller
+    /// does not need to know where the nul byte is located.
     ///
     /// If the first byte is a nul character, this method will return an
     /// empty `CStr`. If multiple nul characters are present, the `CStr` will
@@ -341,7 +341,8 @@ impl CStr {
         }
     }
 
-    /// Creates a C string wrapper from a byte slice.
+    /// Creates a C string wrapper from a byte slice with exactly one nul
+    /// terminator.
     ///
     /// This function will cast the provided `bytes` to a `CStr`
     /// wrapper after ensuring that the byte slice is nul-terminated
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 3f9230aa5d5..d658be0b8eb 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -113,9 +113,9 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     }
     let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
     let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
-    let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
+    let mut fmt_override = ignore::overrides::OverrideBuilder::new(&build.src);
     for ignore in rustfmt_config.ignore {
-        ignore_fmt.add(&format!("!{ignore}")).expect(&ignore);
+        fmt_override.add(&format!("!{ignore}")).expect(&ignore);
     }
     let git_available = match Command::new("git")
         .arg("--version")
@@ -152,6 +152,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                 .map(|entry| {
                     entry.split(' ').nth(1).expect("every git status entry should list a path")
                 });
+            let mut untracked_count = 0;
             for untracked_path in untracked_paths {
                 println!("skip untracked path {untracked_path} during rustfmt invocations");
                 // The leading `/` makes it an exact match against the
@@ -159,7 +160,8 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                 // have `foo.rs` in the repository root it will also match
                 // against anything like `compiler/rustc_foo/src/foo.rs`,
                 // preventing the latter from being formatted.
-                ignore_fmt.add(&format!("!/{untracked_path}")).expect(&untracked_path);
+                untracked_count += 1;
+                fmt_override.add(&format!("!/{untracked_path}")).expect(&untracked_path);
             }
             // Only check modified files locally to speed up runtime.
             // We still check all files in CI to avoid bugs in `get_modified_rs_files` letting regressions slip through;
@@ -172,10 +174,25 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                                 println!("formatting modified file {file}");
                             }
                         } else {
-                            println!("formatting {} modified files", files.len());
+                            let pluralized = |count| if count > 1 { "files" } else { "file" };
+                            let untracked_msg = if untracked_count == 0 {
+                                "".to_string()
+                            } else {
+                                format!(
+                                    ", skipped {} untracked {}",
+                                    untracked_count,
+                                    pluralized(untracked_count),
+                                )
+                            };
+                            println!(
+                                "formatting {} modified {}{}",
+                                files.len(),
+                                pluralized(files.len()),
+                                untracked_msg
+                            );
                         }
                         for file in files {
-                            ignore_fmt.add(&format!("/{file}")).expect(&file);
+                            fmt_override.add(&format!("/{file}")).expect(&file);
                         }
                     }
                     Ok(None) => {}
@@ -196,7 +213,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
         println!("Could not find usable git. Skipping git-aware format checks");
     }
 
-    let ignore_fmt = ignore_fmt.build().unwrap();
+    let fmt_override = fmt_override.build().unwrap();
 
     let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {
         eprintln!("./x.py fmt is not supported on this channel");
@@ -252,7 +269,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
         None => WalkBuilder::new(src.clone()),
     }
     .types(matcher)
-    .overrides(ignore_fmt)
+    .overrides(fmt_override)
     .build_parallel();
 
     // there is a lot of blocking involved in spawning a child process and reading files to format.
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index d8718d26848..81b88d5de98 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -24,7 +24,6 @@ use crate::util::{self, exe, output, t, up_to_date};
 use crate::{CLang, GitRepo, Kind};
 
 use build_helper::ci::CiEnv;
-use build_helper::git::get_git_merge_base;
 
 #[derive(Clone)]
 pub struct LlvmResult {
@@ -129,19 +128,13 @@ pub fn prebuilt_llvm_config(
 /// This retrieves the LLVM sha we *want* to use, according to git history.
 pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
     let llvm_sha = if is_git {
-        // We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we
-        // walk back further to the last bors merge commit that actually changed LLVM. The first
-        // step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD`
-        // in that case.
-        let closest_upstream =
-            get_git_merge_base(Some(&config.src)).unwrap_or_else(|_| "HEAD".into());
         let mut rev_list = config.git();
         rev_list.args(&[
             PathBuf::from("rev-list"),
             format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
             "-n1".into(),
             "--first-parent".into(),
-            closest_upstream.into(),
+            "HEAD".into(),
             "--".into(),
             config.src.join("src/llvm-project"),
             config.src.join("src/bootstrap/download-ci-llvm-stamp"),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6ec8f516366..a5efcc989f6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -370,9 +370,8 @@ fn clean_poly_trait_predicate<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> Option<WherePredicate> {
     // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
-    if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst
-        && Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
-    {
+    // FIXME(effects) check constness
+    if Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() {
         return None;
     }
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index baf90b6d73e..944d0145de2 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -480,12 +480,6 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
     cx: &mut DocContext<'_>,
     item_def_id: DefId,
 ) -> impl Iterator<Item = Item> {
-    // FIXME: To be removed once `parallel_compiler` bugs are fixed!
-    // More information in <https://github.com/rust-lang/rust/pull/106930>.
-    if cfg!(parallel_compiler) {
-        return vec![].into_iter().chain(vec![].into_iter());
-    }
-
     let auto_impls = cx
         .sess()
         .prof
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index f20b7a2b4d7..66876e02c19 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -78,22 +78,13 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
 /// We will then fall back to origin/master in the hope that at least this exists.
 pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
     let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
-    for upstream_master in [format!("{upstream_remote}/master"), format!("origin/master")] {
-        if rev_exists(&upstream_master, git_dir)? {
-            return Ok(upstream_master);
-        }
+    let upstream_master = format!("{upstream_remote}/master");
+    if rev_exists(&upstream_master, git_dir)? {
+        return Ok(upstream_master);
     }
 
-    Err(format!("Cannot find any suitable upstream master branch"))
-}
-
-pub fn get_git_merge_base(git_dir: Option<&Path>) -> Result<String, String> {
-    let updated_master = updated_master_branch(git_dir)?;
-    let mut git = Command::new("git");
-    if let Some(git_dir) = git_dir {
-        git.current_dir(git_dir);
-    }
-    Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
+    // We could implement smarter logic here in the future.
+    Ok("origin/master".into())
 }
 
 /// Returns the files that have been modified in the current branch compared to the master branch.
@@ -103,13 +94,20 @@ pub fn get_git_modified_files(
     git_dir: Option<&Path>,
     extensions: &Vec<&str>,
 ) -> Result<Option<Vec<String>>, String> {
-    let merge_base = get_git_merge_base(git_dir)?;
+    let Ok(updated_master) = updated_master_branch(git_dir) else {
+        return Ok(None);
+    };
 
-    let mut git = Command::new("git");
-    if let Some(git_dir) = git_dir {
-        git.current_dir(git_dir);
-    }
-    let files = output_result(git.args(["diff-index", "--name-only", merge_base.trim()]))?
+    let git = || {
+        let mut git = Command::new("git");
+        if let Some(git_dir) = git_dir {
+            git.current_dir(git_dir);
+        }
+        git
+    };
+
+    let merge_base = output_result(git().arg("merge-base").arg(&updated_master).arg("HEAD"))?;
+    let files = output_result(git().arg("diff-index").arg("--name-only").arg(merge_base.trim()))?
         .lines()
         .map(|s| s.trim().to_owned())
         .filter(|f| {
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject c91a693e7977e33a1064b63a5daf5fb689f0165
+Subproject 020651c52257052d28f6fd83fbecf5cfa1ed516
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index e3f2026cfe9..9900dbdee6b 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
+    self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
     ToPredicate, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -523,7 +523,6 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         if let ClauseKind::Trait(p) = p.kind().skip_binder()
             && p.trait_ref.def_id == eq_trait_id
             && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
-            && p.constness == BoundConstness::NotConst
         {
             // Flag types which already have an `Eq` bound.
             params[self_ty.index as usize].1 = false;
@@ -535,7 +534,6 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 ClauseKind::Trait(TraitPredicate {
                     trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
-                    constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
                 })
                 .to_predicate(tcx)
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 8d6fb8438b6..ba7957b0dec 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -10,7 +10,7 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPat
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, BoundConstness, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
+    self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
     GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -171,7 +171,6 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                                     = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
                                         cx.param_env,
                                         Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                        BoundConstness::NotConst,
                                         ImplPolarity::Positive,
                                     ) && path_to_local(callee)
                                         .map_or(
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index a98e2038d5f..f0a777c5b89 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -16,7 +16,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::{ImplSource, ObligationCause, BuiltinImplSource};
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
 use rustc_semver::RustcVersion;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -399,11 +399,12 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
             return true;
         }
 
+        // FIXME(effects) constness
         let obligation = Obligation::new(
             tcx,
             ObligationCause::dummy_with_span(body.span),
             ConstCx::new(tcx, body).param_env,
-            TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]).with_constness(BoundConstness::ConstIfConst),
+            TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]),
         );
 
         let infcx = tcx.infer_ctxt().build();
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index d0e15aa8bb3..71766480535 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -267,7 +267,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
         cause: ObligationCause::dummy(),
         param_env,
         recursion_depth: 0,
-        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+        predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
     };
     infcx
         .evaluate_obligation(&obligation)
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 8059fddb100..e929091b396 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -18,7 +18,7 @@ use rustc_middle::ty::{
     layout::{HasParamEnv, LayoutOf},
     Ty,
 };
-use rustc_target::abi::{Abi, Size};
+use rustc_target::abi::{Abi, Align, Size};
 
 use crate::borrow_tracker::{
     stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
@@ -619,6 +619,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
         retag_info: RetagInfo, // diagnostics info about this retag
     ) -> InterpResult<'tcx, Option<AllocId>> {
         let this = self.eval_context_mut();
+        // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
+        this.check_ptr_access_align(place.ptr, size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
 
         // It is crucial that this gets called on all code paths, to ensure we track tag creation.
         let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
@@ -707,18 +709,6 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
         let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
         log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
 
-        // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
-        let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?;
-        if base_offset + size > alloc_size {
-            throw_ub!(PointerOutOfBounds {
-                alloc_id,
-                alloc_size,
-                ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
-                ptr_size: size,
-                msg: CheckInAllocMsg::InboundsTest
-            });
-        }
-
         trace!(
             "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
             new_tag,
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 9073f695442..b2dbe8a70f0 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -1,6 +1,6 @@
 use log::trace;
 
-use rustc_target::abi::{Abi, Size};
+use rustc_target::abi::{Abi, Align, Size};
 
 use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields};
 use rustc_middle::{
@@ -182,6 +182,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
         new_tag: BorTag,
     ) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> {
         let this = self.eval_context_mut();
+        // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
+        this.check_ptr_access_align(place.ptr, ptr_size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
 
         // It is crucial that this gets called on all code paths, to ensure we track tag creation.
         let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
@@ -202,51 +204,33 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
         };
 
         trace!("Reborrow of size {:?}", ptr_size);
-        let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO {
-            this.ptr_get_alloc_id(place.ptr)?
-        } else {
-            match this.ptr_try_get_alloc_id(place.ptr) {
-                Ok(data) => data,
-                Err(_) => {
-                    // This pointer doesn't come with an AllocId, so there's no
-                    // memory to do retagging in.
-                    trace!(
-                        "reborrow of size 0: reference {:?} derived from {:?} (pointee {})",
-                        new_tag,
-                        place.ptr,
-                        place.layout.ty,
-                    );
-                    log_creation(this, None)?;
-                    return Ok(None);
-                }
+        let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr) {
+            Ok(data) => {
+                // Unlike SB, we *do* a proper retag for size 0 if can identify the allocation.
+                // After all, the pointer may be lazily initialized outside this initial range.
+                data
+            },
+            Err(_) => {
+                assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
+                // This pointer doesn't come with an AllocId, so there's no
+                // memory to do retagging in.
+                trace!(
+                    "reborrow of size 0: reference {:?} derived from {:?} (pointee {})",
+                    new_tag,
+                    place.ptr,
+                    place.layout.ty,
+                );
+                log_creation(this, None)?;
+                return Ok(None);
             }
         };
+        log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
+
         let orig_tag = match parent_prov {
             ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers
             ProvenanceExtra::Concrete(tag) => tag,
         };
 
-        // Protection against trying to get a reference to a vtable:
-        // vtables do not have an alloc_extra so the call to
-        // `get_alloc_extra` that follows fails.
-        let (alloc_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
-        if ptr_size == Size::ZERO && !matches!(alloc_kind, AllocKind::LiveData) {
-            return Ok(Some((alloc_id, orig_tag)));
-        }
-
-        log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
-
-        // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
-        if base_offset + ptr_size > alloc_size {
-            throw_ub!(PointerOutOfBounds {
-                alloc_id,
-                alloc_size,
-                ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
-                ptr_size,
-                msg: CheckInAllocMsg::InboundsTest
-            });
-        }
-
         trace!(
             "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
             new_tag,
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index ec70b7042df..62f6d57ef36 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -206,7 +206,7 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>:
     ) -> InterpResult<'tcx, Option<Id>> {
         let this = self.eval_context_mut();
         let value_place =
-            this.deref_operand_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
+            this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
 
         // Since we are lazy, this update has to be atomic.
         let (old, success) = this
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index d41bcc978b0..f9a8bad3a4f 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -715,9 +715,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     }
 
     /// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
-    fn deref_operand_as(
+    fn deref_pointer_as(
         &self,
-        op: &OpTy<'tcx, Provenance>,
+        op: &impl Readable<'tcx, Provenance>,
         layout: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
         let this = self.eval_context_ref();
@@ -746,15 +746,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     }
 
     /// Calculates the MPlaceTy given the offset and layout of an access on an operand
-    fn deref_operand_and_offset(
+    fn deref_pointer_and_offset(
         &self,
-        op: &OpTy<'tcx, Provenance>,
+        op: &impl Readable<'tcx, Provenance>,
         offset: u64,
         base_layout: TyAndLayout<'tcx>,
         value_layout: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
         let this = self.eval_context_ref();
-        let op_place = this.deref_operand_as(op, base_layout)?;
+        let op_place = this.deref_pointer_as(op, base_layout)?;
         let offset = Size::from_bytes(offset);
 
         // Ensure that the access is within bounds.
@@ -763,28 +763,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         Ok(value_place)
     }
 
-    fn read_scalar_at_offset(
+    fn deref_pointer_and_read(
         &self,
-        op: &OpTy<'tcx, Provenance>,
+        op: &impl Readable<'tcx, Provenance>,
         offset: u64,
         base_layout: TyAndLayout<'tcx>,
         value_layout: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, Scalar<Provenance>> {
         let this = self.eval_context_ref();
-        let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
+        let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
         this.read_scalar(&value_place)
     }
 
-    fn write_scalar_at_offset(
+    fn deref_pointer_and_write(
         &mut self,
-        op: &OpTy<'tcx, Provenance>,
+        op: &impl Readable<'tcx, Provenance>,
         offset: u64,
         value: impl Into<Scalar<Provenance>>,
         base_layout: TyAndLayout<'tcx>,
         value_layout: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
-        let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
+        let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
         this.write_scalar(value, &value_place)
     }
 
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 9f4bb37a469..a3297bf819f 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             1 => {
                 let [_flags, buf] = this.check_shim(abi, Abi::Rust, link_name, args)?;
 
-                let buf_place = this.deref_operand(buf)?;
+                let buf_place = this.deref_pointer(buf)?;
 
                 let ptr_layout = this.layout_of(ptr_ty)?;
 
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 763fa9235d0..167d1fd4518 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -418,9 +418,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         //     // First thing: load all the arguments. Details depend on the shim.
         //     let arg1 = this.read_scalar(arg1)?.to_u32()?;
         //     let arg2 = this.read_pointer(arg2)?; // when you need to work with the pointer directly
-        //     let arg3 = this.deref_operand_as(arg3, this.libc_ty_layout("some_libc_struct"))?; // when you want to load/store
+        //     let arg3 = this.deref_pointer_as(arg3, this.libc_ty_layout("some_libc_struct"))?; // when you want to load/store
         //         // through the pointer and supply the type information yourself
-        //     let arg4 = this.deref_operand(arg4)?; // when you want to load/store through the pointer and trust
+        //     let arg4 = this.deref_pointer(arg4)?; // when you want to load/store through the pointer and trust
         //         // the user-given type (which you shouldn't usually do)
         //
         //     // ...
diff --git a/src/tools/miri/src/shims/intrinsics/atomic.rs b/src/tools/miri/src/shims/intrinsics/atomic.rs
index 50f69bdca36..e38b677f485 100644
--- a/src/tools/miri/src/shims/intrinsics/atomic.rs
+++ b/src/tools/miri/src/shims/intrinsics/atomic.rs
@@ -130,7 +130,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
 
         let [place] = check_arg_count(args)?;
-        let place = this.deref_operand(place)?;
+        let place = this.deref_pointer(place)?;
 
         // Perform atomic load.
         let val = this.read_scalar_atomic(&place, atomic)?;
@@ -147,7 +147,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
 
         let [place, val] = check_arg_count(args)?;
-        let place = this.deref_operand(place)?;
+        let place = this.deref_pointer(place)?;
 
         // Perform regular load.
         let val = this.read_scalar(val)?;
@@ -188,7 +188,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
 
         let [place, rhs] = check_arg_count(args)?;
-        let place = this.deref_operand(place)?;
+        let place = this.deref_pointer(place)?;
         let rhs = this.read_immediate(rhs)?;
 
         if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() {
@@ -229,7 +229,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
 
         let [place, new] = check_arg_count(args)?;
-        let place = this.deref_operand(place)?;
+        let place = this.deref_pointer(place)?;
         let new = this.read_scalar(new)?;
 
         let old = this.atomic_exchange_scalar(&place, new, atomic)?;
@@ -248,7 +248,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
 
         let [place, expect_old, new] = check_arg_count(args)?;
-        let place = this.deref_operand(place)?;
+        let place = this.deref_pointer(place)?;
         let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()`
         let new = this.read_scalar(new)?;
 
diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs
index 26f0a660657..c900ced19cd 100644
--- a/src/tools/miri/src/shims/intrinsics/mod.rs
+++ b/src/tools/miri/src/shims/intrinsics/mod.rs
@@ -96,12 +96,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // Raw memory accesses
             "volatile_load" => {
                 let [place] = check_arg_count(args)?;
-                let place = this.deref_operand(place)?;
+                let place = this.deref_pointer(place)?;
                 this.copy_op(&place, dest, /*allow_transmute*/ false)?;
             }
             "volatile_store" => {
                 let [place, dest] = check_arg_count(args)?;
-                let place = this.deref_operand(place)?;
+                let place = this.deref_pointer(place)?;
                 this.copy_op(dest, &place, /*allow_transmute*/ false)?;
             }
 
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index 103feae4ae7..b6225713cd0 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -534,7 +534,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let dest = this.project_index(&dest, i)?;
 
                     let val = if simd_element_to_bool(mask)? {
-                        let place = this.deref_operand(&ptr)?;
+                        let place = this.deref_pointer(&ptr)?;
                         this.read_immediate(&place)?
                     } else {
                         passthru
@@ -557,7 +557,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let mask = this.read_immediate(&this.project_index(&mask, i)?)?;
 
                     if simd_element_to_bool(mask)? {
-                        let place = this.deref_operand(&ptr)?;
+                        let place = this.deref_pointer(&ptr)?;
                         this.write_immediate(*value, &place)?;
                     }
                 }
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 935447fd89d..d6d0483f5e3 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -25,7 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         this.assert_target_os_is_unix("clock_gettime");
 
         let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
-        let tp = this.deref_operand_as(tp_op, this.libc_ty_layout("timespec"))?;
+        let tp = this.deref_pointer_as(tp_op, this.libc_ty_layout("timespec"))?;
 
         let absolute_clocks;
         let mut relative_clocks;
@@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         this.assert_target_os_is_unix("gettimeofday");
         this.check_no_isolation("`gettimeofday`")?;
 
-        let tv = this.deref_operand_as(tv_op, this.libc_ty_layout("timeval"))?;
+        let tv = this.deref_pointer_as(tv_op, this.libc_ty_layout("timeval"))?;
 
         // Using tz is obsolete and should always be null
         let tz = this.read_pointer(tz_op)?;
@@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         this.assert_target_os("windows", "GetSystemTimeAsFileTime");
         this.check_no_isolation("`GetSystemTimeAsFileTime`")?;
 
-        let filetime = this.deref_operand_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?;
+        let filetime = this.deref_pointer_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?;
 
         let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
         let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
@@ -156,7 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let qpc = i64::try_from(duration.as_nanos()).map_err(|_| {
             err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported")
         })?;
-        this.write_scalar(Scalar::from_i64(qpc), &this.deref_operand(lpPerformanceCount_op)?)?;
+        this.write_scalar(Scalar::from_i64(qpc), &this.deref_pointer(lpPerformanceCount_op)?)?;
         Ok(Scalar::from_i32(-1)) // return non-zero on success
     }
 
@@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         // and thus 10^9 counts per second.
         this.write_scalar(
             Scalar::from_i64(1_000_000_000),
-            &this.deref_operand_as(lpFrequency_op, this.machine.layouts.u64)?,
+            &this.deref_pointer_as(lpFrequency_op, this.machine.layouts.u64)?,
         )?;
         Ok(Scalar::from_i32(-1)) // Return non-zero on success
     }
@@ -203,7 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         this.assert_target_os("macos", "mach_timebase_info");
 
-        let info = this.deref_operand_as(info_op, this.libc_ty_layout("mach_timebase_info"))?;
+        let info = this.deref_pointer_as(info_op, this.libc_ty_layout("mach_timebase_info"))?;
 
         // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds,
         // no scaling needs to happen.
@@ -222,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         this.assert_target_os_is_unix("nanosleep");
 
-        let req = this.deref_operand_as(req_op, this.libc_ty_layout("timespec"))?;
+        let req = this.deref_pointer_as(req_op, this.libc_ty_layout("timespec"))?;
 
         let duration = match this.read_timespec(&req)? {
             Some(duration) => duration,
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 5f3c15c5874..3a480190535 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // Allocation
             "posix_memalign" => {
                 let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let ret = this.deref_operand(ret)?;
+                let ret = this.deref_pointer(ret)?;
                 let align = this.read_target_usize(align)?;
                 let size = this.read_target_usize(size)?;
                 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
@@ -271,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // Thread-local storage
             "pthread_key_create" => {
                 let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let key_place = this.deref_operand_as(key, this.libc_ty_layout("pthread_key_t"))?;
+                let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
                 let dtor = this.read_pointer(dtor)?;
 
                 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
@@ -506,7 +506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             "pthread_attr_getguardsize"
             if this.frame_in_std() => {
                 let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let guard_size = this.deref_operand(guard_size)?;
+                let guard_size = this.deref_pointer(guard_size)?;
                 let guard_size_layout = this.libc_ty_layout("size_t");
                 this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?;
 
@@ -532,9 +532,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 // Hence we can mostly ignore the input `attr_place`.
                 let [attr_place, addr_place, size_place] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let _attr_place = this.deref_operand_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
-                let addr_place = this.deref_operand(addr_place)?;
-                let size_place = this.deref_operand(size_place)?;
+                let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
+                let addr_place = this.deref_pointer(addr_place)?;
+                let size_place = this.deref_pointer(size_place)?;
 
                 this.write_scalar(
                     Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
@@ -575,10 +575,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.check_no_isolation("`getpwuid_r`")?;
 
                 let uid = this.read_scalar(uid)?.to_u32()?;
-                let pwd = this.deref_operand_as(pwd, this.libc_ty_layout("passwd"))?;
+                let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
                 let buf = this.read_pointer(buf)?;
                 let buflen = this.read_target_usize(buflen)?;
-                let result = this.deref_operand(result)?;
+                let result = this.deref_pointer(result)?;
 
                 // Must be for "us".
                 if uid != crate::shims::unix::UID {
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index fe5b01e7610..09349bfdead 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -344,7 +344,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx
         let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0));
         let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));
 
-        let buf = this.deref_operand_as(buf_op, this.libc_ty_layout("stat"))?;
+        let buf = this.deref_pointer_as(buf_op, this.libc_ty_layout("stat"))?;
 
         this.write_int_fields_named(
             &[
@@ -1014,7 +1014,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             return Ok(-1);
         }
 
-        let statxbuf = this.deref_operand_as(statxbuf_op, this.libc_ty_layout("statx"))?;
+        let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
 
         let path = this.read_path_from_c_str(pathname_ptr)?.into_owned();
         // See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
@@ -1420,7 +1420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 //     pub d_name: [c_char; 1024],
                 // }
 
-                let entry_place = this.deref_operand_as(entry_op, this.libc_ty_layout("dirent"))?;
+                let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
                 let name_place = this.project_field(&entry_place, 5)?;
 
                 let file_name = dir_entry.file_name(); // not a Path as there are no separators!
@@ -1456,14 +1456,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     &entry_place,
                 )?;
 
-                let result_place = this.deref_operand(result_op)?;
+                let result_place = this.deref_pointer(result_op)?;
                 this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
 
                 0
             }
             None => {
                 // end of stream: return 0, assign *result=NULL
-                this.write_null(&this.deref_operand(result_op)?)?;
+                this.write_null(&this.deref_pointer(result_op)?)?;
                 0
             }
             Some(Err(e)) =>
diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs
index 92966319f19..f2be89ce637 100644
--- a/src/tools/miri/src/shims/unix/linux/fd.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd.rs
@@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let epoll_ctl_del = this.eval_libc_i32("EPOLL_CTL_DEL");
 
         if op == epoll_ctl_add || op == epoll_ctl_mod {
-            let event = this.deref_operand_as(event, this.libc_ty_layout("epoll_event"))?;
+            let event = this.deref_pointer_as(event, this.libc_ty_layout("epoll_event"))?;
 
             let events = this.project_field(&event, 0)?;
             let events = this.read_scalar(&events)?.to_u32()?;
@@ -240,7 +240,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let _domain = this.read_scalar(domain)?.to_i32()?;
         let _type_ = this.read_scalar(type_)?.to_i32()?;
         let _protocol = this.read_scalar(protocol)?.to_i32()?;
-        let sv = this.deref_operand(sv)?;
+        let sv = this.deref_pointer(sv)?;
 
         let fh = &mut this.machine.file_handler;
         let sv0 = fh.insert_fd(Box::new(SocketPair));
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index a97cc49d88e..1bd751c5981 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -198,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.read_scalar(pid)?.to_i32()?;
                 this.read_target_usize(cpusetsize)?;
-                this.deref_operand_as(mask, this.libc_ty_layout("cpu_set_t"))?;
+                this.deref_pointer_as(mask, this.libc_ty_layout("cpu_set_t"))?;
                 // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`.
                 let einval = this.eval_libc("EINVAL");
                 this.set_last_error(einval)?;
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 5141b29b683..f073daab8ed 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.check_no_isolation("`_NSGetExecutablePath`")?;
 
                 let buf_ptr = this.read_pointer(buf)?;
-                let bufsize = this.deref_operand(bufsize)?;
+                let bufsize = this.deref_pointer(bufsize)?;
 
                 // Using the host current_exe is a bit off, but consistent with Linux
                 // (where stdlib reads /proc/self/exe).
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index 0aeb8ae95a7..6666ffbd1d5 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -36,7 +36,7 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>(
     ecx: &MiriInterpCx<'mir, 'tcx>,
     attr_op: &OpTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, i32> {
-    ecx.read_scalar_at_offset(
+    ecx.deref_pointer_and_read(
         attr_op,
         0,
         ecx.libc_ty_layout("pthread_mutexattr_t"),
@@ -50,7 +50,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>(
     attr_op: &OpTy<'tcx, Provenance>,
     kind: i32,
 ) -> InterpResult<'tcx, ()> {
-    ecx.write_scalar_at_offset(
+    ecx.deref_pointer_and_write(
         attr_op,
         0,
         Scalar::from_i32(kind),
@@ -79,7 +79,7 @@ fn mutex_reset_id<'mir, 'tcx: 'mir>(
     ecx: &mut MiriInterpCx<'mir, 'tcx>,
     mutex_op: &OpTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, ()> {
-    ecx.write_scalar_at_offset(
+    ecx.deref_pointer_and_write(
         mutex_op,
         4,
         Scalar::from_i32(0),
@@ -93,7 +93,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>(
     mutex_op: &OpTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, i32> {
     let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
-    ecx.read_scalar_at_offset(
+    ecx.deref_pointer_and_read(
         mutex_op,
         offset,
         ecx.libc_ty_layout("pthread_mutex_t"),
@@ -108,7 +108,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>(
     kind: i32,
 ) -> InterpResult<'tcx, ()> {
     let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
-    ecx.write_scalar_at_offset(
+    ecx.deref_pointer_and_write(
         mutex_op,
         offset,
         Scalar::from_i32(kind),
@@ -141,7 +141,7 @@ fn condattr_get_clock_id<'mir, 'tcx: 'mir>(
     ecx: &MiriInterpCx<'mir, 'tcx>,
     attr_op: &OpTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, i32> {
-    ecx.read_scalar_at_offset(
+    ecx.deref_pointer_and_read(
         attr_op,
         0,
         ecx.libc_ty_layout("pthread_condattr_t"),
@@ -155,7 +155,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>(
     attr_op: &OpTy<'tcx, Provenance>,
     clock_id: i32,
 ) -> InterpResult<'tcx, ()> {
-    ecx.write_scalar_at_offset(
+    ecx.deref_pointer_and_write(
         attr_op,
         0,
         Scalar::from_i32(clock_id),
@@ -184,7 +184,7 @@ fn cond_reset_id<'mir, 'tcx: 'mir>(
     ecx: &mut MiriInterpCx<'mir, 'tcx>,
     cond_op: &OpTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, ()> {
-    ecx.write_scalar_at_offset(
+    ecx.deref_pointer_and_write(
         cond_op,
         4,
         Scalar::from_i32(0),
@@ -197,7 +197,7 @@ fn cond_get_clock_id<'mir, 'tcx: 'mir>(
     ecx: &MiriInterpCx<'mir, 'tcx>,
     cond_op: &OpTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, i32> {
-    ecx.read_scalar_at_offset(
+    ecx.deref_pointer_and_read(
         cond_op,
         8,
         ecx.libc_ty_layout("pthread_cond_t"),
@@ -211,7 +211,7 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>(
     cond_op: &OpTy<'tcx, Provenance>,
     clock_id: i32,
 ) -> InterpResult<'tcx, ()> {
-    ecx.write_scalar_at_offset(
+    ecx.deref_pointer_and_write(
         cond_op,
         8,
         Scalar::from_i32(clock_id),
@@ -346,7 +346,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         // This can always be revisited to have some external state to catch double-destroys
         // but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933
         this.write_uninit(
-            &this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
+            &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
         )?;
 
         Ok(0)
@@ -500,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // This might lead to false positives, see comment in pthread_mutexattr_destroy
         this.write_uninit(
-            &this.deref_operand_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
+            &this.deref_pointer_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
         )?;
         // FIXME: delete interpreter state associated with this mutex.
 
@@ -625,7 +625,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // This might lead to false positives, see comment in pthread_mutexattr_destroy
         this.write_uninit(
-            &this.deref_operand_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
+            &this.deref_pointer_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
         )?;
         // FIXME: delete interpreter state associated with this rwlock.
 
@@ -675,7 +675,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
 
         let clock_id = condattr_get_clock_id(this, attr_op)?;
-        this.write_scalar(Scalar::from_i32(clock_id), &this.deref_operand(clk_id_op)?)?;
+        this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?;
 
         Ok(Scalar::from_i32(0))
     }
@@ -691,7 +691,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // This might lead to false positives, see comment in pthread_mutexattr_destroy
         this.write_uninit(
-            &this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
+            &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
         )?;
 
         Ok(0)
@@ -784,7 +784,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         // Extract the timeout.
         let clock_id = cond_get_clock_id(this, cond_op)?;
         let duration = match this
-            .read_timespec(&this.deref_operand_as(abstime_op, this.libc_ty_layout("timespec"))?)?
+            .read_timespec(&this.deref_pointer_as(abstime_op, this.libc_ty_layout("timespec"))?)?
         {
             Some(duration) => duration,
             None => {
@@ -867,7 +867,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         cond_get_clock_id(this, cond_op)?;
 
         // This might lead to false positives, see comment in pthread_mutexattr_destroy
-        this.write_uninit(&this.deref_operand_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
+        this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
         // FIXME: delete interpreter state associated with this condvar.
 
         Ok(0)
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 30ed110ca83..259689348ad 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
-        let thread_info_place = this.deref_operand_as(thread, this.libc_ty_layout("pthread_t"))?;
+        let thread_info_place = this.deref_pointer_as(thread, this.libc_ty_layout("pthread_t"))?;
 
         let start_routine = this.read_pointer(start_routine)?;
 
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 2f95cfb8bab..cb90ed57ffe 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -91,7 +91,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let n = this.read_scalar(n)?.to_u32()?;
                 let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
                 let io_status_block = this
-                    .deref_operand_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
+                    .deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
 
                 if byte_offset != 0 {
                     throw_unsup_format!(
@@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [system_info] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 let system_info =
-                    this.deref_operand_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
+                    this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
                 // Initialize with `0`.
                 this.write_bytes_ptr(
                     system_info.ptr,
@@ -391,8 +391,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [console, buffer_info] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 this.read_target_isize(console)?;
-                // FIXME: this should use deref_operand_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
-                this.deref_operand(buffer_info)?;
+                // FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
+                this.deref_pointer(buffer_info)?;
                 // Indicate an error.
                 // FIXME: we should set last_error, but to what?
                 this.write_null(dest)?;
@@ -508,7 +508,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [console, mode] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 this.read_target_isize(console)?;
-                this.deref_operand(mode)?;
+                this.deref_pointer(mode)?;
                 // Indicate an error.
                 this.write_null(dest)?;
             }
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index 5d5cf73797f..c8c8173aa51 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let id = this.init_once_get_id(init_once_op)?;
         let flags = this.read_scalar(flags_op)?.to_u32()?;
-        let pending_place = this.deref_operand(pending_op)?.into();
+        let pending_place = this.deref_pointer(pending_op)?.into();
         let context = this.read_pointer(context_op)?;
 
         if flags != 0 {
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index 9cbae158859..3953a881a72 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? {
             None
         } else {
-            let thread_info_place = this.deref_operand(thread_op)?;
+            let thread_info_place = this.deref_pointer(thread_op)?;
             Some(thread_info_place)
         };
 
diff --git a/src/tools/miri/tests/fail/alloc/deallocate-twice.rs b/src/tools/miri/tests/fail/alloc/deallocate-twice.rs
index f07bbda4a9b..7a3ff84b2cb 100644
--- a/src/tools/miri/tests/fail/alloc/deallocate-twice.rs
+++ b/src/tools/miri/tests/fail/alloc/deallocate-twice.rs
@@ -1,6 +1,6 @@
 use std::alloc::{alloc, dealloc, Layout};
 
-//@error-in-other-file: dereferenced after this allocation got freed
+//@error-in-other-file: has been freed
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr b/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr
index fa7a74ee13c..23d145e7d30 100644
--- a/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr
+++ b/src/tools/miri/tests/fail/alloc/deallocate-twice.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
   --> RUSTLIB/alloc/src/alloc.rs:LL:CC
    |
 LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/alloc/reallocate-change-alloc.rs b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs
index 3ad56da2c2f..ecdd3ae5fee 100644
--- a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs
+++ b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.rs
@@ -4,6 +4,6 @@ fn main() {
     unsafe {
         let x = alloc(Layout::from_size_align_unchecked(1, 1));
         let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1);
-        let _z = *x; //~ ERROR: dereferenced after this allocation got freed
+        let _z = *x; //~ ERROR: has been freed
     }
 }
diff --git a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr
index 5631dcb4cc0..7c7cec211b7 100644
--- a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr
+++ b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/reallocate-change-alloc.rs:LL:CC
    |
 LL |         let _z = *x;
-   |                  ^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                  ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/alloc/reallocate-dangling.rs b/src/tools/miri/tests/fail/alloc/reallocate-dangling.rs
index 130e2a8301e..622348ad190 100644
--- a/src/tools/miri/tests/fail/alloc/reallocate-dangling.rs
+++ b/src/tools/miri/tests/fail/alloc/reallocate-dangling.rs
@@ -1,6 +1,6 @@
 use std::alloc::{alloc, dealloc, realloc, Layout};
 
-//@error-in-other-file: dereferenced after this allocation got freed
+//@error-in-other-file: has been freed
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr b/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr
index b1460bfb763..9c222154716 100644
--- a/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr
+++ b/src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
   --> RUSTLIB/alloc/src/alloc.rs:LL:CC
    |
 LL |     unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/both_borrows/illegal_write1.rs b/src/tools/miri/tests/fail/both_borrows/illegal_write1.rs
index d3991949cc3..92f273f67bb 100644
--- a/src/tools/miri/tests/fail/both_borrows/illegal_write1.rs
+++ b/src/tools/miri/tests/fail/both_borrows/illegal_write1.rs
@@ -1,6 +1,8 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
 
+#![allow(invalid_reference_casting)]
+
 fn main() {
     let target = Box::new(42); // has an implicit raw
     let xref = &*target;
diff --git a/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.rs b/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.rs
index d89c670b632..d5e6d37226a 100644
--- a/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.rs
+++ b/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.rs
@@ -11,6 +11,6 @@ unsafe impl Send for SendRaw {}
 fn main() {
     unsafe {
         let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap();
-        let _val = *dangling_ptr.0; //~ ERROR: dereferenced after this allocation got freed
+        let _val = *dangling_ptr.0; //~ ERROR: has been freed
     }
 }
diff --git a/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr b/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr
index cc3e5639878..0cb8aa29001 100644
--- a/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr
+++ b/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/thread_local_static_dealloc.rs:LL:CC
    |
 LL |         let _val = *dangling_ptr.0;
-   |                    ^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                    ^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/dangling_pointer_addr_of.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs
index 4249c1cbf01..49f3ae306a0 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs
@@ -7,6 +7,6 @@ fn main() {
         let b = Box::new(42);
         &*b as *const i32
     };
-    let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: dereferenced after this allocation got freed
+    let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: has been freed
     panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr
index 5f081afe68a..398f216e731 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/dangling_pointer_addr_of.rs:LL:CC
    |
 LL |     let x = unsafe { ptr::addr_of!(*p) };
-   |                      ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                      ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/dangling_pointer_deref.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.rs
index ad2a599b60b..675e3e15da8 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.rs
@@ -6,6 +6,6 @@ fn main() {
         let b = Box::new(42);
         &*b as *const i32
     };
-    let x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed
+    let x = unsafe { *p }; //~ ERROR: has been freed
     panic!("this should never print: {}", x);
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr
index cb323818845..cb95d71a605 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/dangling_pointer_deref.rs:LL:CC
    |
 LL |     let x = unsafe { *p };
-   |                      ^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                      ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/dangling_pointer_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs
new file mode 100644
index 00000000000..65eca07a070
--- /dev/null
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs
@@ -0,0 +1,11 @@
+// Make sure we find these even with many checks disabled.
+//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
+
+fn main() {
+    let p = {
+        let b = Box::new(42);
+        &*b as *const i32
+    };
+    let x = unsafe { p.offset(42) }; //~ ERROR: /out-of-bounds pointer arithmetic: .* has been freed/
+    panic!("this should never print: {:?}", x);
+}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr
new file mode 100644
index 00000000000..85bd2bed9c3
--- /dev/null
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+  --> $DIR/dangling_pointer_offset.rs:LL:CC
+   |
+LL |     let x = unsafe { p.offset(42) };
+   |                      ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+   |
+   = 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
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/dangling_pointer_offset.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs
index 7c5f440b774..4c641243950 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs
@@ -7,7 +7,7 @@ fn main() {
         &*b as *const i32
     };
     unsafe {
-        let _ = *p; //~ ERROR: dereferenced after this allocation got freed
+        let _ = *p; //~ ERROR: has been freed
     }
     panic!("this should never print");
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr
index 7b76389c753..f2d58fe7697 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr
@@ -1,13 +1,13 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
-  --> $DIR/dangling_pointer_deref_underscore.rs:LL:CC
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
+  --> $DIR/dangling_pointer_project_underscore.rs:LL:CC
    |
 LL |         let _ = *p;
-   |                 ^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                 ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/dangling_pointer_deref_underscore.rs:LL:CC
+   = note: inside `main` at $DIR/dangling_pointer_project_underscore.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs
index e749eb896e2..a1fefe04ab6 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs
@@ -6,5 +6,5 @@ fn main() {
         let b = Box::new(42);
         &*b as *const i32 as *const ()
     };
-    let _x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed
+    let _x = unsafe { *p }; //~ ERROR: has been freed
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr
index 02db6302a0a..c15f17f3b82 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/dangling_zst_deref.rs:LL:CC
    |
 LL |     let _x = unsafe { *p };
-   |                       ^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                       ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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.rs b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.rs
index c193d5fe0b3..5f8a1988b3c 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.rs
@@ -8,7 +8,7 @@ unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 {
 fn main() {
     unsafe {
         let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"!
-        let val = *x; //~ ERROR: dereferenced after this allocation got freed
+        let val = *x; //~ ERROR: has been freed
         println!("{}", val);
     }
 }
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 679e4809ca6..500f28a3cbc 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/stack_temporary.rs:LL:CC
    |
 LL |         let val = *x;
-   |                   ^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                   ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/data_race/dealloc_read_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs
index 5d7a0cc1dc9..c921ce6b716 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs
@@ -32,7 +32,7 @@ pub fn main() {
             let ptr = ptr; // avoid field capturing
             // Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Read on thread `<unnamed>`
             // but the invalid allocation is detected first.
-            *ptr.0 //~ ERROR: dereferenced after this allocation got freed
+            *ptr.0 //~ ERROR: has been freed
         });
 
         j1.join().unwrap();
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr
index f303d57c8bd..4efc35c15e2 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr
+++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/dealloc_read_race2.rs:LL:CC
    |
 LL |             *ptr.0
-   |             ^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |             ^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/data_race/dealloc_write_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs
index a7f43f03c02..e01132202d4 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs
@@ -31,7 +31,7 @@ pub fn main() {
             let ptr = ptr; // avoid field capturing
             // Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Write on thread `<unnamed>`
             // but the invalid allocation is detected first.
-            *ptr.0 = 2; //~ ERROR: dereferenced after this allocation got freed
+            *ptr.0 = 2; //~ ERROR: has been freed
         });
 
         j1.join().unwrap();
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr
index 23b8e9ade0e..fad525830e6 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr
+++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/dealloc_write_race2.rs:LL:CC
    |
 LL |             *ptr.0 = 2;
-   |             ^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |             ^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/environ-gets-deallocated.rs b/src/tools/miri/tests/fail/environ-gets-deallocated.rs
index e4597140b84..6dcf1fdb1c7 100644
--- a/src/tools/miri/tests/fail/environ-gets-deallocated.rs
+++ b/src/tools/miri/tests/fail/environ-gets-deallocated.rs
@@ -20,5 +20,5 @@ fn main() {
     let pointer = get_environ();
     let _x = unsafe { *pointer };
     std::env::set_var("FOO", "BAR");
-    let _y = unsafe { *pointer }; //~ ERROR: dereferenced after this allocation got freed
+    let _y = unsafe { *pointer }; //~ ERROR: has been freed
 }
diff --git a/src/tools/miri/tests/fail/environ-gets-deallocated.stderr b/src/tools/miri/tests/fail/environ-gets-deallocated.stderr
index a2d343bf865..6332846d5d8 100644
--- a/src/tools/miri/tests/fail/environ-gets-deallocated.stderr
+++ b/src/tools/miri/tests/fail/environ-gets-deallocated.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/environ-gets-deallocated.rs:LL:CC
    |
 LL |     let _y = unsafe { *pointer };
-   |                       ^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                       ^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/generator-pinned-moved.rs b/src/tools/miri/tests/fail/generator-pinned-moved.rs
index 29dc6e56f7c..33348ace9c4 100644
--- a/src/tools/miri/tests/fail/generator-pinned-moved.rs
+++ b/src/tools/miri/tests/fail/generator-pinned-moved.rs
@@ -13,7 +13,7 @@ fn firstn() -> impl Generator<Yield = u64, Return = ()> {
         *num += 0;
 
         yield *num;
-        *num += 1; //~ERROR: dereferenced after this allocation got freed
+        *num += 1; //~ERROR: has been freed
     }
 }
 
diff --git a/src/tools/miri/tests/fail/generator-pinned-moved.stderr b/src/tools/miri/tests/fail/generator-pinned-moved.stderr
index 80c5794736a..3eb17f05584 100644
--- a/src/tools/miri/tests/fail/generator-pinned-moved.stderr
+++ b/src/tools/miri/tests/fail/generator-pinned-moved.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/generator-pinned-moved.rs:LL:CC
    |
 LL |         *num += 1;
-   |         ^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |         ^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/rc_as_ptr.rs b/src/tools/miri/tests/fail/rc_as_ptr.rs
index 6aea1870748..ebcf49b8f99 100644
--- a/src/tools/miri/tests/fail/rc_as_ptr.rs
+++ b/src/tools/miri/tests/fail/rc_as_ptr.rs
@@ -16,5 +16,5 @@ fn main() {
     drop(strong);
     // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to
     // undefined behaviour.
-    assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: dereferenced after this allocation got freed
+    assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: has been freed
 }
diff --git a/src/tools/miri/tests/fail/rc_as_ptr.stderr b/src/tools/miri/tests/fail/rc_as_ptr.stderr
index 70bdd157bdc..129916ac73c 100644
--- a/src/tools/miri/tests/fail/rc_as_ptr.stderr
+++ b/src/tools/miri/tests/fail/rc_as_ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/rc_as_ptr.rs:LL:CC
    |
 LL |     assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/shims/mmap_use_after_munmap.rs b/src/tools/miri/tests/fail/shims/mmap_use_after_munmap.rs
index 1e00bc6b64f..c97b013ba5a 100644
--- a/src/tools/miri/tests/fail/shims/mmap_use_after_munmap.rs
+++ b/src/tools/miri/tests/fail/shims/mmap_use_after_munmap.rs
@@ -14,6 +14,6 @@ fn main() {
             0,
         );
         libc::munmap(ptr, 4096);
-        let _x = *(ptr as *mut u8); //~ ERROR: was dereferenced after this allocation got freed
+        let _x = *(ptr as *mut u8); //~ ERROR: has been freed
     }
 }
diff --git a/src/tools/miri/tests/fail/shims/mmap_use_after_munmap.stderr b/src/tools/miri/tests/fail/shims/mmap_use_after_munmap.stderr
index f90701d400c..8b9969da8fd 100644
--- a/src/tools/miri/tests/fail/shims/mmap_use_after_munmap.stderr
+++ b/src/tools/miri/tests/fail/shims/mmap_use_after_munmap.stderr
@@ -13,11 +13,11 @@ LL |         libc::munmap(ptr, 4096);
    = note: BACKTRACE:
    = note: inside `main` at $DIR/mmap_use_after_munmap.rs:LL:CC
 
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/mmap_use_after_munmap.rs:LL:CC
    |
 LL |         let _x = *(ptr as *mut u8);
-   |                  ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |                  ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/stacked_borrows/illegal_write3.rs b/src/tools/miri/tests/fail/stacked_borrows/illegal_write3.rs
index 6f55b63cb5c..f79f7b561b8 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write3.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_write3.rs
@@ -1,3 +1,5 @@
+#![allow(invalid_reference_casting)]
+
 fn main() {
     let target = 42;
     // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref.
diff --git a/src/tools/miri/tests/fail/zst2.rs b/src/tools/miri/tests/fail/zst2.rs
index 1d3e8ea9d00..04218c264a3 100644
--- a/src/tools/miri/tests/fail/zst2.rs
+++ b/src/tools/miri/tests/fail/zst2.rs
@@ -8,5 +8,5 @@ fn main() {
     let mut x_box = Box::new(1u8);
     let x = &mut *x_box as *mut _ as *mut [u8; 0];
     drop(x_box);
-    unsafe { *x = zst_val }; //~ ERROR: dereferenced after this allocation got freed
+    unsafe { *x = zst_val }; //~ ERROR: has been freed
 }
diff --git a/src/tools/miri/tests/fail/zst2.stderr b/src/tools/miri/tests/fail/zst2.stderr
index 6c49656e4c6..63f40ed2067 100644
--- a/src/tools/miri/tests/fail/zst2.stderr
+++ b/src/tools/miri/tests/fail/zst2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
+error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
   --> $DIR/zst2.rs:LL:CC
    |
 LL |     unsafe { *x = zst_val };
-   |              ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
+   |              ^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs
index 4e9d3626aa8..9af9b5ca458 100644
--- a/tests/ui/const-generics/issues/issue-100313.rs
+++ b/tests/ui/const-generics/issues/issue-100313.rs
@@ -9,6 +9,7 @@ impl <const B: &'static bool> T<B> {
         unsafe {
             *(B as *const bool as *mut bool) = false;
             //~^ ERROR evaluation of constant value failed [E0080]
+            //~| ERROR assigning to `&T` is undefined behavior
         }
     }
 }
diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr
index d4b486376ca..42ad4d61c8e 100644
--- a/tests/ui/const-generics/issues/issue-100313.stderr
+++ b/tests/ui/const-generics/issues/issue-100313.stderr
@@ -1,3 +1,11 @@
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/issue-100313.rs:10:13
+   |
+LL |             *(B as *const bool as *mut bool) = false;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(invalid_reference_casting)]` on by default
+
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-100313.rs:10:13
    |
@@ -10,11 +18,11 @@ note: inside `T::<&true>::set_false`
 LL |             *(B as *const bool as *mut bool) = false;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: inside `_`
-  --> $DIR/issue-100313.rs:18:5
+  --> $DIR/issue-100313.rs:19:5
    |
 LL |     x.set_false();
    |     ^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
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 4eb1c42e1f7..b50ef0c68a1 100644
--- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
+++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
@@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/dealloc_intrinsic_dangling.rs:10:5
    |
 LL |     &*ptr
-   |     ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
+   |     ^^^^^ dereferencing pointer failed: alloc2 has been freed, so this pointer is dangling
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/dealloc_intrinsic_dangling.rs:18:5
    |
 LL |     *reference
-   |     ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed
+   |     ^^^^^^^^^^ dereferencing pointer failed: alloc4 has been freed, so this pointer is dangling
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr
index 8177a08504b..0884ade45a7 100644
--- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr
+++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/dealloc_intrinsic_duplicate.rs:9:5
    |
 LL |     intrinsics::const_deallocate(ptr, 4, 4);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc2 has been freed, so this pointer is dangling
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/const-eval/issue-49296.stderr b/tests/ui/consts/const-eval/issue-49296.stderr
index cc4f1594c32..45ba0ea183e 100644
--- a/tests/ui/consts/const-eval/issue-49296.stderr
+++ b/tests/ui/consts/const-eval/issue-49296.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/issue-49296.rs:9:16
    |
 LL | const X: u64 = *wat(42);
-   |                ^^^^^^^^ pointer to alloc3 was dereferenced after this allocation got freed
+   |                ^^^^^^^^ dereferencing pointer failed: alloc3 has been freed, so this pointer is dangling
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/const-float-classify.rs b/tests/ui/consts/const-float-classify.rs
index 3a5d5bb46e9..877ce02193c 100644
--- a/tests/ui/consts/const-float-classify.rs
+++ b/tests/ui/consts/const-float-classify.rs
@@ -1,5 +1,6 @@
 // compile-flags: -Zmir-opt-level=0
-// run-pass
+// known-bug: #110395
+// FIXME run-pass
 
 #![feature(const_float_bits_conv)]
 #![feature(const_float_classify)]
diff --git a/tests/ui/consts/const-float-classify.stderr b/tests/ui/consts/const-float-classify.stderr
new file mode 100644
index 00000000000..a23d81c0ebe
--- /dev/null
+++ b/tests/ui/consts/const-float-classify.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<A as MyEq<B>>::eq` in constant functions
+  --> $DIR/const-float-classify.rs:31:7
+   |
+LL |     x.eq(y)
+   |       ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr
index d4a445120a2..6eee466611c 100644
--- a/tests/ui/consts/constifconst-call-in-const-position.stderr
+++ b/tests/ui/consts/constifconst-call-in-const-position.stderr
@@ -7,12 +7,22 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0080]: evaluation of `foo::<()>::{constant#0}` failed
+error[E0015]: cannot call non-const fn `<T as Tr>::a` in constants
+  --> $DIR/constifconst-call-in-const-position.rs:17:9
+   |
+LL |     [0; T::a()]
+   |         ^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<T as Tr>::a` in constants
   --> $DIR/constifconst-call-in-const-position.rs:16:38
    |
 LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
-   |                                      ^^^^^^ calling non-const function `<() as Tr>::a`
+   |                                      ^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/ptr_comparisons.rs b/tests/ui/consts/ptr_comparisons.rs
index f442e613839..a5b6cd9d2d4 100644
--- a/tests/ui/consts/ptr_comparisons.rs
+++ b/tests/ui/consts/ptr_comparisons.rs
@@ -1,8 +1,5 @@
 // compile-flags: --crate-type=lib
-// normalize-stderr-32bit: "8 bytes" -> "$$TWO_WORDS bytes"
-// normalize-stderr-64bit: "16 bytes" -> "$$TWO_WORDS bytes"
-// normalize-stderr-32bit: "size 4" -> "size $$WORD"
-// normalize-stderr-64bit: "size 8" -> "size $$WORD"
+// check-pass
 
 #![feature(
     core_intrinsics,
@@ -34,30 +31,13 @@ check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0);
 
 // We want pointers to be equal to themselves, but aren't checking this yet because
 // there are some open questions (e.g. whether function pointers to the same function
-// compare equal, they don't necessarily at runtime).
-// The case tested here should work eventually, but does not work yet.
+// compare equal: they don't necessarily do at runtime).
 check!(!, FOO as *const _, FOO as *const _);
 
+// aside from 0, these pointers might end up pretty much anywhere.
+check!(!, FOO as *const _, 1); // this one could be `ne` by taking into account alignment
+check!(!, FOO as *const _, 1024);
 
-///////////////////////////////////////////////////////////////////////////////
-// If any of the below start compiling, make sure to add a `check` test for it.
-// These invocations exist as canaries so we don't forget to check that the
-// behaviour of `guaranteed_eq` and `guaranteed_ne` is still correct.
-// All of these try to obtain an out of bounds pointer in some manner. If we
-// can create out of bounds pointers, we can offset a pointer far enough that
-// at runtime it would be zero and at compile-time it would not be zero.
-
-const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
-
-const _: *const u8 =
-    unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
-//~^ ERROR evaluation of constant value failed
-//~| out-of-bounds
-
-const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
-//~^ ERROR evaluation of constant value failed
-//~| unable to turn pointer into raw bytes
-
-const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
-//~^ ERROR evaluation of constant value failed
-//~| unable to turn pointer into raw bytes
+// When pointers go out-of-bounds, they *might* become null, so these comparions cannot work.
+check!(!, unsafe { (FOO as *const usize).wrapping_add(2) }, 0);
+check!(!, unsafe { (FOO as *const usize).wrapping_sub(1) }, 0);
diff --git a/tests/ui/consts/ptr_comparisons.stderr b/tests/ui/consts/ptr_comparisons.stderr
deleted file mode 100644
index fea924d12e5..00000000000
--- a/tests/ui/consts/ptr_comparisons.stderr
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0080]: evaluation of constant value failed
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
-   |
-note: inside `ptr::const_ptr::<impl *const usize>::offset`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `_`
-  --> $DIR/ptr_comparisons.rs:50:34
-   |
-LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ptr_comparisons.rs:53:33
-   |
-LL |     unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ptr_comparisons.rs:57:27
-   |
-LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = 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]: evaluation of constant value failed
-  --> $DIR/ptr_comparisons.rs:61:27
-   |
-LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = 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: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.rs b/tests/ui/consts/unstable-const-fn-in-libcore.rs
index ca4ed8f0b47..61e28117ed4 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.rs
@@ -20,6 +20,7 @@ impl<T> Opt<T> {
         match self {
             Opt::Some(t) => t,
             Opt::None => f(),
+            //~^ ERROR cannot call
         }
     }
 }
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index e5b00dd07ab..95d7b7e8537 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,3 +1,15 @@
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/unstable-const-fn-in-libcore.rs:22:26
+   |
+LL |             Opt::None => f(),
+   |                          ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T + ~const std::ops::FnOnce<()>>(self, f: F) -> T {
+   |                                                     +++++++++++++++++++++++++++++
+
 error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:17:60
    |
@@ -16,6 +28,7 @@ LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
 LL |     }
    |     - value is dropped here
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0493`.
+Some errors have detailed explanations: E0015, E0493.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/generic-const-items/const-trait-impl.rs b/tests/ui/generic-const-items/const-trait-impl.rs
index 8da1448df4f..d30f7af170d 100644
--- a/tests/ui/generic-const-items/const-trait-impl.rs
+++ b/tests/ui/generic-const-items/const-trait-impl.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 
 // Test that we can call methods from const trait impls inside of generic const items.
 
diff --git a/tests/ui/generic-const-items/const-trait-impl.stderr b/tests/ui/generic-const-items/const-trait-impl.stderr
new file mode 100644
index 00000000000..34360c581d5
--- /dev/null
+++ b/tests/ui/generic-const-items/const-trait-impl.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as Create>::create` in constants
+  --> $DIR/const-trait-impl.rs:11:37
+   |
+LL | const CREATE<T: ~const Create>: T = T::create();
+   |                                     ^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index 06247e2ea1e..5fbba9a85ca 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,3 +1,15 @@
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/normalize-tait-in-const.rs:26:5
+   |
+LL |     fun(filter_positive());
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct + ~const std::ops::Fn<(&Alias<'_>,)>>(fun: F) {
+   |                                                                              ++++++++++++++++++++++++++++++++++++
+
 error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/normalize-tait-in-const.rs:25:79
    |
@@ -7,6 +19,7 @@ LL |     fun(filter_positive());
 LL | }
    | - value is dropped here
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0493`.
+Some errors have detailed explanations: E0015, E0493.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/imports/resolve-other-libc.rs b/tests/ui/imports/resolve-other-libc.rs
new file mode 100644
index 00000000000..806d854ec89
--- /dev/null
+++ b/tests/ui/imports/resolve-other-libc.rs
@@ -0,0 +1,14 @@
+// Regression test for https://github.com/rust-lang/rust/issues/26043
+
+// compile-flags: --extern libc=test.rlib
+
+// The error shall NOT be something similar to the following, because it
+// indicates that `libc` was wrongly resolved to `libc` shipped with the
+// compiler:
+//
+//   error[E0658]: use of unstable library feature 'rustc_private': \
+//           this crate is being loaded from the sysroot
+//
+extern crate libc; //~ ERROR: extern location for libc does not exist: test.rlib
+
+fn main() {}
diff --git a/tests/ui/imports/resolve-other-libc.stderr b/tests/ui/imports/resolve-other-libc.stderr
new file mode 100644
index 00000000000..e57b88e50c6
--- /dev/null
+++ b/tests/ui/imports/resolve-other-libc.stderr
@@ -0,0 +1,8 @@
+error: extern location for libc does not exist: test.rlib
+  --> $DIR/resolve-other-libc.rs:12:1
+   |
+LL | extern crate libc;
+   | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs
index 9963820499e..6e70626ef99 100644
--- a/tests/ui/lint/reference_casting.rs
+++ b/tests/ui/lint/reference_casting.rs
@@ -1,7 +1,6 @@
 // check-fail
 
 #![feature(ptr_from_ref)]
-#![deny(invalid_reference_casting)]
 
 extern "C" {
     // N.B., mutability can be easily incorrect in FFI calls -- as
@@ -10,42 +9,63 @@ extern "C" {
     fn int_ffi(c: *mut i32);
 }
 
-fn main() {
+unsafe fn ref_to_mut() {
+    let num = &3i32;
+
+    let _num = &mut *(num as *const i32 as *mut i32);
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    let _num = &mut *(num as *const i32).cast_mut();
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    let _num = &mut *std::ptr::from_ref(num).cast_mut();
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    let _num = &mut *std::ptr::from_ref({ num }).cast_mut();
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut();
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+    let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+
+    let deferred = num as *const i32 as *mut i32;
+    let _num = &mut *deferred;
+    //~^ ERROR casting `&T` to `&mut T` is undefined behavior
+}
+
+unsafe fn assign_to_ref() {
     let s = String::from("Hello");
     let a = &s;
-    unsafe {
-        let num = &3i32;
-        let mut_num = &mut 3i32;
-
-        (*(a as *const _ as *mut String)).push_str(" world");
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        *(a as *const _ as *mut _) = String::from("Replaced");
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        *(a as *const _ as *mut String) += " world";
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        let _num = &mut *(num as *const i32 as *mut i32);
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        let _num = &mut *(num as *const i32).cast_mut();
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        let _num = *{ num as *const i32 }.cast_mut();
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        *std::ptr::from_ref(num).cast_mut() += 1;
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        *std::ptr::from_ref({ num }).cast_mut() += 1;
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        *{ std::ptr::from_ref(num) }.cast_mut() += 1;
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-        *(std::ptr::from_ref({ num }) as *mut i32) += 1;
-        //~^ ERROR casting `&T` to `&mut T` is undefined behavior
-
-        // Shouldn't be warned against
-        println!("{}", *(num as *const _ as *const i16));
-        println!("{}", *(mut_num as *mut _ as *mut i16));
-        ffi(a.as_ptr() as *mut _);
-        int_ffi(num as *const _ as *mut _);
-        int_ffi(&3 as *const _ as *mut _);
-        let mut value = 3;
-        let value: *const i32 = &mut value;
-        *(value as *const i16 as *mut i16) = 42;
-    }
+    let num = &3i32;
+
+    *(a as *const _ as *mut _) = String::from("Replaced");
+    //~^ ERROR assigning to `&T` is undefined behavior
+    *(a as *const _ as *mut String) += " world";
+    //~^ ERROR assigning to `&T` is undefined behavior
+    *std::ptr::from_ref(num).cast_mut() += 1;
+    //~^ ERROR assigning to `&T` is undefined behavior
+    *std::ptr::from_ref({ num }).cast_mut() += 1;
+    //~^ ERROR assigning to `&T` is undefined behavior
+    *{ std::ptr::from_ref(num) }.cast_mut() += 1;
+    //~^ ERROR assigning to `&T` is undefined behavior
+    *(std::ptr::from_ref({ num }) as *mut i32) += 1;
+    //~^ ERROR assigning to `&T` is undefined behavior
+    let value = num as *const i32 as *mut i32;
+    *value = 1;
+    //~^ ERROR assigning to `&T` is undefined behavior
 }
+
+unsafe fn no_warn() {
+    let num = &3i32;
+    let mut_num = &mut 3i32;
+    let a = &String::from("ffi");
+
+    *(num as *const i32 as *mut i32);
+    println!("{}", *(num as *const _ as *const i16));
+    println!("{}", *(mut_num as *mut _ as *mut i16));
+    ffi(a.as_ptr() as *mut _);
+    int_ffi(num as *const _ as *mut _);
+    int_ffi(&3 as *const _ as *mut _);
+    let mut value = 3;
+    let value: *const i32 = &mut value;
+    *(value as *const i16 as *mut i16) = 42;
+}
+
+fn main() {}
diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr
index d5b9bbef643..02b23600557 100644
--- a/tests/ui/lint/reference_casting.stderr
+++ b/tests/ui/lint/reference_casting.stderr
@@ -1,68 +1,92 @@
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:20:9
+  --> $DIR/reference_casting.rs:15:16
    |
-LL |         (*(a as *const _ as *mut String)).push_str(" world");
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _num = &mut *(num as *const i32 as *mut i32);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the lint level is defined here
-  --> $DIR/reference_casting.rs:4:9
-   |
-LL | #![deny(invalid_reference_casting)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(invalid_reference_casting)]` on by default
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:22:9
+  --> $DIR/reference_casting.rs:17:16
    |
-LL |         *(a as *const _ as *mut _) = String::from("Replaced");
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _num = &mut *(num as *const i32).cast_mut();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:24:9
+  --> $DIR/reference_casting.rs:19:16
    |
-LL |         *(a as *const _ as *mut String) += " world";
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _num = &mut *std::ptr::from_ref(num).cast_mut();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:26:25
+  --> $DIR/reference_casting.rs:21:16
    |
-LL |         let _num = &mut *(num as *const i32 as *mut i32);
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _num = &mut *std::ptr::from_ref({ num }).cast_mut();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:28:25
+  --> $DIR/reference_casting.rs:23:16
    |
-LL |         let _num = &mut *(num as *const i32).cast_mut();
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:30:20
+  --> $DIR/reference_casting.rs:25:16
    |
-LL |         let _num = *{ num as *const i32 }.cast_mut();
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:32:9
+  --> $DIR/reference_casting.rs:29:16
    |
-LL |         *std::ptr::from_ref(num).cast_mut() += 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let deferred = num as *const i32 as *mut i32;
+   |                    ----------------------------- casting happend here
+LL |     let _num = &mut *deferred;
+   |                ^^^^^^^^^^^^^^
 
-error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:34:9
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:38:5
    |
-LL |         *std::ptr::from_ref({ num }).cast_mut() += 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     *(a as *const _ as *mut _) = String::from("Replaced");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:36:9
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:40:5
    |
-LL |         *{ std::ptr::from_ref(num) }.cast_mut() += 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     *(a as *const _ as *mut String) += " world";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/reference_casting.rs:38:9
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:42:5
+   |
+LL |     *std::ptr::from_ref(num).cast_mut() += 1;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:44:5
+   |
+LL |     *std::ptr::from_ref({ num }).cast_mut() += 1;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:46:5
+   |
+LL |     *{ std::ptr::from_ref(num) }.cast_mut() += 1;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:48:5
+   |
+LL |     *(std::ptr::from_ref({ num }) as *mut i32) += 1;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
+  --> $DIR/reference_casting.rs:51:5
    |
-LL |         *(std::ptr::from_ref({ num }) as *mut i32) += 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let value = num as *const i32 as *mut i32;
+   |                 ----------------------------- casting happend here
+LL |     *value = 1;
+   |     ^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs
index 780a510c500..a70ef31fed1 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 #![feature(const_trait_impl)]
 
 #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr
new file mode 100644
index 00000000000..6d7980a9736
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<<T as Foo>::Assoc as Foo>::foo` in constant functions
+  --> $DIR/assoc-type-const-bound-usage.rs:12:5
+   |
+LL |     <T as Foo>::Assoc::foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
index c350e3e4061..96ffca6519a 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
@@ -1,21 +1,15 @@
-error[E0080]: evaluation of constant value failed
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-   = note: calling non-const function `<() as Tr>::a`
-   |
-note: inside `<fn(()) -> i32 {<() as Tr>::a} as FnOnce<((),)>>::call_once - shim(fn(()) -> i32 {<() as Tr>::a})`
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-note: inside `need_const_closure::<fn(()) -> i32 {<() as Tr>::a}>`
+error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/const-closure-trait-method-fail.rs:15:5
    |
 LL |     x(())
    |     ^^^^^
-note: inside `_`
-  --> $DIR/const-closure-trait-method-fail.rs:18:23
    |
-LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const std::ops::FnOnce<((),)>>(x: T) -> i32 {
+   |                                                         ++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs
index 3e6d1908848..fd9f287250d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 #![feature(const_trait_impl)]
 
 #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
new file mode 100644
index 00000000000..fd0c2911814
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
@@ -0,0 +1,15 @@
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closure-trait-method.rs:15:5
+   |
+LL |     x(())
+   |     ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const std::ops::FnOnce<((),)>>(x: T) -> i32 {
+   |                                                         ++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs
index 7c55b51c8f5..1fe4044d527 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 
 #![feature(const_trait_impl)]
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
new file mode 100644
index 00000000000..abf2a2dc511
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
@@ -0,0 +1,39 @@
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closures.rs:12:5
+   |
+LL |     f() * 7
+   |     ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL |         F: ~const FnOnce() -> u8 + ~const std::ops::Fn<()>,
+   |                                  +++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closures.rs:24:5
+   |
+LL |     f() + f()
+   |     ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn answer<F: ~const Fn() -> u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 {
+   |                                      +++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closures.rs:24:11
+   |
+LL |     f() + f()
+   |           ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn answer<F: ~const Fn() -> u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 {
+   |                                      +++++++++++++++++++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr
index ce27e42f8c2..7de33003c48 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr
@@ -1,3 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions
+  --> $DIR/const-drop-fail-2.rs:25:9
+   |
+LL |         T::a();
+   |         ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/const-drop-fail-2.rs:29:36
    |
@@ -6,6 +14,15 @@ LL | const fn check<T: ~const Destruct>(_: T) {}
    |                                    |
    |                                    the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to previous error
+error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions
+  --> $DIR/const-drop-fail-2.rs:39:9
+   |
+LL |         T::a();
+   |         ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0493`.
+Some errors have detailed explanations: E0015, E0493.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
index 23e36887025..b28584e7e36 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
@@ -14,6 +14,15 @@ LL |     let _ = S(&mut c);
    |             |
    |             the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 2 previous errors
+error[E0015]: cannot call non-const fn `<T as SomeTrait>::foo` in constant functions
+  --> $DIR/const-drop.rs:70:13
+   |
+LL |             T::foo();
+   |             ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0493`.
+Some errors have detailed explanations: E0015, E0493.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
index 23e36887025..b28584e7e36 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
@@ -14,6 +14,15 @@ LL |     let _ = S(&mut c);
    |             |
    |             the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 2 previous errors
+error[E0015]: cannot call non-const fn `<T as SomeTrait>::foo` in constant functions
+  --> $DIR/const-drop.rs:70:13
+   |
+LL |             T::foo();
+   |             ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0493`.
+Some errors have detailed explanations: E0015, E0493.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
index 6ffdfa13132..f5644c8883d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
@@ -13,7 +13,7 @@ const fn foo<T>() where T: ~const Tr {}
 pub trait Foo {
     fn foo() {
         foo::<()>();
-        //FIXME ~^ ERROR the trait bound `(): ~const Tr` is not satisfied
+        //FIXME ~^ ERROR the trait bound `(): Tr` is not satisfied
     }
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
index fe51c1f1ca3..c21c73f40f2 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+error[E0277]: the trait bound `(): Tr` is not satisfied
   --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
    |
 LL |         ().a()
-   |            ^ the trait `~const Tr` is not implemented for `()`
+   |            ^ the trait `Tr` is not implemented for `()`
    |
    = help: the trait `Tr` is implemented for `()`
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs
index 0701cf93a02..3db59631ef8 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs
@@ -1,6 +1,7 @@
 // Tests that trait bounds on specializing trait impls must be `~const` if the
 // same bound is present on the default impl and is `~const` there.
-// known-bug: #110395
+// check-pass
+// FIXME(effects) ^ should error
 
 #![feature(const_trait_impl)]
 #![feature(rustc_attrs)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
deleted file mode 100644
index 8f5ca2189da..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: missing `~const` qualifier for specialization
-  --> $DIR/const-default-bound-non-const-specialized-bound.rs:33:8
-   |
-LL |     T: Foo, //FIXME ~ ERROR missing `~const` qualifier
-   |        ^^^
-
-error: missing `~const` qualifier for specialization
-  --> $DIR/const-default-bound-non-const-specialized-bound.rs:53:8
-   |
-LL |     T: Foo,
-   |        ^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs
index 9ddea427cfd..307d5a37bb0 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs
@@ -1,7 +1,8 @@
 // Tests that a const default trait impl can be specialized by another const
 // trait impl and that the specializing impl will be used during const-eval.
 
-// run-pass
+// known-bug: #110395
+// FIXME run-pass
 
 #![feature(const_trait_impl)]
 #![feature(min_specialization)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
new file mode 100644
index 00000000000..6dad82b03b5
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
+  --> $DIR/const-default-const-specialized.rs:16:5
+   |
+LL |     T::value()
+   |     ^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs
index 35aa52fbd4e..f1fbbb512e3 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs
@@ -1,7 +1,7 @@
 // Tests that a non-const default impl can be specialized by a const trait impl,
 // but that the default impl cannot be used in a const context.
-
-// run-pass
+// known-bug: #110395
+// FIXME run-pass
 
 #![feature(const_trait_impl)]
 #![feature(min_specialization)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
new file mode 100644
index 00000000000..5ba4f2d52c5
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
+  --> $DIR/non-const-default-const-specialized.rs:15:5
+   |
+LL |     T::value()
+   |     ^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs
index 5c2a3f80170..0a28da9e65e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs
@@ -22,7 +22,7 @@ impl<T: ~const Spec> const A for T {
 
 impl<T: Spec + Sup> A for T {
 //~^ ERROR: cannot specialize
-//~| ERROR: missing `~const` qualifier
+//FIXME(effects) ~| ERROR: missing `~const` qualifier
     fn a() -> u32 {
         3
     }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr
index 1ffdc50e589..08258fd1a57 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr
@@ -4,11 +4,5 @@ error: cannot specialize on const impl with non-const impl
 LL | impl<T: Spec + Sup> A for T {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: missing `~const` qualifier for specialization
-  --> $DIR/specializing-constness.rs:23:9
-   |
-LL | impl<T: Spec + Sup> A for T {
-   |         ^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
index fdc6b805889..2897eabb081 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
@@ -1,17 +1,17 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:12:19
+  --> $DIR/super-traits-fail-3.rs:13:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
 
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:12:19
+  --> $DIR/super-traits-fail-3.rs:13:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
 
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:16:24
+  --> $DIR/super-traits-fail-3.rs:17:24
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
    |                        ^^^
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
index 7375b8c819c..9839a4f2480 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
@@ -1,11 +1,11 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:12:19
+  --> $DIR/super-traits-fail-3.rs:13:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
 
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:12:19
+  --> $DIR/super-traits-fail-3.rs:13:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
index 8cf64944ac1..16c592830d7 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
@@ -1,7 +1,8 @@
 #![feature(const_trait_impl)]
 
 // revisions: yy yn ny nn
-//[yy] check-pass
+//[yy] known-bug: #110395
+//FIXME [yy] check-pass
 
 #[cfg_attr(any(yy, yn), const_trait)]
 trait Foo {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
index 7a152914b69..58225b94591 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
@@ -1,5 +1,5 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:16:24
+  --> $DIR/super-traits-fail-3.rs:17:24
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
    |                        ^^^
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr
new file mode 100644
index 00000000000..6bc643e6871
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:19:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
index df96f6fb4ab..79cba548fd5 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 #![feature(const_trait_impl)]
 
 #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr
new file mode 100644
index 00000000000..03d7b0549a6
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits.rs:21:7
+   |
+LL |     t.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
index 78a64b9018a..7338fb245b3 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
@@ -24,6 +24,7 @@ impl const Add42 for () {
 
 fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
     //~^ ERROR `~const` is not allowed here
+    //~| ERROR cannot call
     Foo
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr
index aae72f36e57..2a17ee3f372 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr
@@ -10,5 +10,14 @@ note: this function is not `const`, so it cannot have `~const` trait bounds
 LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
    |    ^^^
 
-error: aborting due to previous error
+error[E0015]: cannot call non-const fn `<A as Add42>::add` in constants
+  --> $DIR/tilde-const-and-const-params.rs:25:61
+   |
+LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+   |                                                             ^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs
index 285cef571f3..411f4b2f68c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 #![feature(const_trait_impl)]
 
 #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.stderr
new file mode 100644
index 00000000000..4b852b65b0c
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as Foo>::foo` in constant functions
+  --> $DIR/tilde_const_on_impl_bound.rs:14:16
+   |
+LL |         self.0.foo()
+   |                ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs
index 90e9afd8e52..47f7806e453 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs
@@ -3,7 +3,7 @@
 // (`rustc_const_eval` instead of `rustc_hir_analysis`) Therefore one file as a
 // test is not enough.
 // known-bug: #110395
-// check-pass
+// FIXME check-pass
 #![feature(const_trait_impl)]
 
 #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
new file mode 100644
index 00000000000..54537231b61
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
@@ -0,0 +1,51 @@
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/trait-where-clause-const.rs:20:5
+   |
+LL |     T::a();
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<T as Foo>::b` in constant functions
+  --> $DIR/trait-where-clause-const.rs:21:5
+   |
+LL |     T::b();
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<T as Foo>::c::<T>` in constant functions
+  --> $DIR/trait-where-clause-const.rs:23:5
+   |
+LL |     T::c::<T>();
+   |     ^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/trait-where-clause-const.rs:28:5
+   |
+LL |     T::a();
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<T as Foo>::b` in constant functions
+  --> $DIR/trait-where-clause-const.rs:29:5
+   |
+LL |     T::b();
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<T as Foo>::c::<T>` in constant functions
+  --> $DIR/trait-where-clause-const.rs:30:5
+   |
+LL |     T::c::<T>();
+   |     ^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs
index 4b8b004069d..29809a2ee56 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs
@@ -1,4 +1,5 @@
-// run-pass
+// known-bug: #110395
+// FIXME run-pass
 
 #![feature(const_trait_impl)]
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr
new file mode 100644
index 00000000000..b353c622b55
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<Self as Bar>::bar` in constant functions
+  --> $DIR/trait-where-clause-run.rs:14:9
+   |
+LL |         <Self as Bar>::bar() * 6
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
index 3b028ac48db..32ebe03435d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: #110395
+// FIXME check-pass
 
 #![feature(const_trait_impl)]
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.stderr
new file mode 100644
index 00000000000..7356fbd9267
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<T as Foo>::bar` in constant functions
+  --> $DIR/trait-where-clause-self-referential.rs:22:5
+   |
+LL |     T::bar();
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.