about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-12-21 17:05:40 +0000
committerMichael Goulet <michael@errs.io>2024-12-22 21:57:57 +0000
commit9a1c5eb5b385adb3cd04af0049cbf5c225cefdc3 (patch)
tree02737d1b8386b3d999cbd1778e315b539f2f6826
parentb22856d192567a55a1d2788fbc3084e3f9cb220f (diff)
downloadrust-9a1c5eb5b385adb3cd04af0049cbf5c225cefdc3.tar.gz
rust-9a1c5eb5b385adb3cd04af0049cbf5c225cefdc3.zip
Begin to implement type system layer of unsafe binders
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs1
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs1
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs98
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs1
-rw-r--r--compiler/rustc_lint/src/types.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs4
-rw-r--r--compiler/rustc_middle/src/ty/error.rs1
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs6
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs5
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs18
-rw-r--r--compiler/rustc_middle/src/ty/util.rs10
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/coherence.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs15
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs15
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs3
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs1
-rw-r--r--compiler/rustc_privacy/src/lib.rs1
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs5
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs3
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs3
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs5
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs5
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
-rw-r--r--compiler/rustc_type_ir/src/binder.rs8
-rw-r--r--compiler/rustc_type_ir/src/fast_reject.rs12
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs3
-rw-r--r--compiler/rustc_type_ir/src/outlives.rs1
-rw-r--r--compiler/rustc_type_ir/src/relate.rs4
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs71
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs4
-rw-r--r--tests/debuginfo/function-names.rs2
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs30
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr176
-rw-r--r--tests/ui/feature-gates/feature-gate-auto-traits.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-auto-traits.stderr2
-rw-r--r--tests/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--tests/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--tests/ui/traits/negative-impls/feature-gate-negative_impls.rs2
-rw-r--r--tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr2
-rw-r--r--tests/ui/unsafe-binders/expr.rs11
-rw-r--r--tests/ui/unsafe-binders/expr.stderr24
-rw-r--r--tests/ui/unsafe-binders/lifetime-resolution.rs7
-rw-r--r--tests/ui/unsafe-binders/lifetime-resolution.stderr24
-rw-r--r--tests/ui/unsafe-binders/mismatch.rs43
-rw-r--r--tests/ui/unsafe-binders/mismatch.stderr68
-rw-r--r--tests/ui/unsafe-binders/simple.rs3
-rw-r--r--tests/ui/unsafe-binders/simple.stderr10
79 files changed, 536 insertions, 305 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index f885b20c761..3fbf1210186 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -263,7 +263,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                         &self,
                         negative_impls,
                         span.to(of_trait.as_ref().map_or(span, |t| t.path.span)),
-                        "negative trait bounds are not yet fully implemented; \
+                        "negative trait bounds are not fully implemented; \
                          use marker types for now"
                     );
                 }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 8ee1b1d0ae6..ac0293848cc 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1613,6 +1613,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     | ty::CoroutineWitness(..)
                     | ty::Never
                     | ty::Tuple(_)
+                    | ty::UnsafeBinder(_)
                     | ty::Alias(_, _)
                     | ty::Param(_)
                     | ty::Bound(_, _)
@@ -1654,6 +1655,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     | ty::Dynamic(_, _, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
+                    | ty::UnsafeBinder(_)
                     | ty::Alias(_, _)
                     | ty::Param(_)
                     | ty::Bound(_, _)
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index cf72c2ed742..869798d8be1 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -432,6 +432,7 @@ fn push_debuginfo_type_name<'tcx>(
                 push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
             }
         }
+        ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
         ty::Param(_)
         | ty::Error(_)
         | ty::Infer(_)
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 6f51b09323d..4ff8aa9a3b4 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -178,7 +178,8 @@ fn const_to_valtree_inner<'tcx>(
         | ty::Closure(..)
         | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
-        | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
+        | ty::CoroutineWitness(..)
+        | ty::UnsafeBinder(_) => Err(ValTreeCreationError::NonSupportedType(ty)),
     }
 }
 
@@ -358,7 +359,10 @@ pub fn valtree_to_const_value<'tcx>(
         | ty::FnPtr(..)
         | ty::Str
         | ty::Slice(_)
-        | ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()),
+        | ty::Dynamic(..)
+        | ty::UnsafeBinder(_) => {
+            bug!("no ValTree should have been created for type {:?}", ty.kind())
+        }
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 1af8438534f..e9eca8814c3 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -90,6 +90,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             | ty::CoroutineClosure(_, _)
             | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
+            | ty::UnsafeBinder(_)
             | ty::Never
             | ty::Tuple(_)
             | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 6512675530a..7d0e0492792 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -505,6 +505,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // We don't want to do any queries, so there is not much we can do with ADTs.
                 ty::Adt(..) => false,
 
+                ty::UnsafeBinder(ty) => is_very_trivially_sized(ty.skip_binder()),
+
                 ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
 
                 ty::Infer(ty::TyVar(_)) => false,
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 6f101395ccf..d75df1ad442 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -768,6 +768,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 // Nothing to check.
                 interp_ok(true)
             }
+            ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
             // The above should be all the primitive types. The rest is compound, we
             // check them by visiting their fields/variants.
             ty::Adt(..)
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 36c7bed5c11..e14cd603c58 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -38,7 +38,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
             | ty::FnPtr(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Dynamic(_, _, _) => self.pretty_print_type(ty),
+            | ty::Dynamic(_, _, _)
+            | ty::UnsafeBinder(_) => self.pretty_print_type(ty),
 
             // Placeholders (all printed as `_` to uniformize them).
             ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 8f6f5b5f222..a86dede48bf 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -178,7 +178,8 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Ref(..)
             | ty::Never
             | ty::FnPtr(..)
-            | ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
+            | ty::Tuple(..)
+            | ty::UnsafeBinder(_) => self.check_primitive_impl(id, self_ty),
             ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) | ty::Param(_) => {
                 Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }))
             }
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index eca85c22a40..7d651155781 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -225,7 +225,8 @@ pub(crate) fn orphan_check_impl(
             | ty::FnDef(..)
             | ty::FnPtr(..)
             | ty::Never
-            | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
+            | ty::Tuple(..)
+            | ty::UnsafeBinder(_) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
 
             ty::Closure(..)
             | ty::CoroutineClosure(..)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index b56222763d0..2154568c512 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2318,13 +2318,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
                 )
             }
-            hir::TyKind::UnsafeBinder(_binder) => {
-                let guar = self
-                    .dcx()
-                    .struct_span_err(hir_ty.span, "unsafe binders are not yet implemented")
-                    .emit();
-                Ty::new_error(tcx, guar)
-            }
+            hir::TyKind::UnsafeBinder(binder) => Ty::new_unsafe_binder(
+                tcx,
+                ty::Binder::bind_with_vars(
+                    self.lower_ty(binder.inner_ty),
+                    tcx.late_bound_vars(hir_ty.hir_id),
+                ),
+            ),
             hir::TyKind::TraitObject(bounds, lifetime, repr) => {
                 if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
                     // Don't continue with type analysis if the `dyn` keyword is missing
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 415b23d812b..e954d2b9ea4 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -322,6 +322,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_sig(current, sig_tys.with(hdr), variance);
             }
 
+            ty::UnsafeBinder(ty) => {
+                // FIXME(unsafe_binders): This is covariant, right?
+                self.add_constraints_from_ty(current, ty.skip_binder(), variance);
+            }
+
             ty::Error(_) => {
                 // we encounter this when walking the trait references for object
                 // types, where we use Error as the Self type
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 8190095971b..7b07e0ee939 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -116,6 +116,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Some(&f) => self.pointer_kind(f, span)?,
             },
 
+            ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+
             // Pointers to foreign types are thin, despite being unsized
             ty::Foreign(..) => Some(PointerKind::Thin),
             // We should really try to normalize here.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index caea53d9200..5e7dc4370d9 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -574,8 +574,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_expr_index(base, idx, expr, brackets_span)
             }
             ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
-            ExprKind::UnsafeBinderCast(kind, expr, ty) => {
-                self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
+            ExprKind::UnsafeBinderCast(kind, inner_expr, ty) => {
+                self.check_expr_unsafe_binder_cast(expr.span, kind, inner_expr, ty, expected)
             }
             ExprKind::Err(guar) => Ty::new_error(tcx, guar),
         }
@@ -1649,14 +1649,94 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn check_expr_unsafe_binder_cast(
         &self,
-        _kind: hir::UnsafeBinderCastKind,
-        expr: &'tcx hir::Expr<'tcx>,
-        _hir_ty: Option<&'tcx hir::Ty<'tcx>>,
-        _expected: Expectation<'tcx>,
+        span: Span,
+        kind: hir::UnsafeBinderCastKind,
+        inner_expr: &'tcx hir::Expr<'tcx>,
+        hir_ty: Option<&'tcx hir::Ty<'tcx>>,
+        expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let guar =
-            self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
-        Ty::new_error(self.tcx, guar)
+        self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
+
+        match kind {
+            hir::UnsafeBinderCastKind::Wrap => {
+                let ascribed_ty =
+                    hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
+                let expected_ty = expected.only_has_type(self);
+                let binder_ty = match (ascribed_ty, expected_ty) {
+                    (Some(ascribed_ty), Some(expected_ty)) => {
+                        self.demand_eqtype(inner_expr.span, expected_ty, ascribed_ty);
+                        expected_ty
+                    }
+                    (Some(ty), None) | (None, Some(ty)) => ty,
+                    // This will always cause a structural resolve error, but we do it
+                    // so we don't need to manually report an E0282 both on this codepath
+                    // and in the others; it all happens in `structurally_resolve_type`.
+                    (None, None) => self.next_ty_var(inner_expr.span),
+                };
+
+                let binder_ty = self.structurally_resolve_type(inner_expr.span, binder_ty);
+                let hint_ty = match *binder_ty.kind() {
+                    ty::UnsafeBinder(binder) => self.instantiate_binder_with_fresh_vars(
+                        inner_expr.span,
+                        infer::BoundRegionConversionTime::HigherRankedType,
+                        binder.into(),
+                    ),
+                    ty::Error(e) => Ty::new_error(self.tcx, e),
+                    _ => {
+                        let guar = self
+                            .dcx()
+                            .struct_span_err(
+                                hir_ty.map_or(span, |hir_ty| hir_ty.span),
+                                format!(
+                                    "`wrap_binder!()` can only wrap into unsafe binder, not {}",
+                                    binder_ty.sort_string(self.tcx)
+                                ),
+                            )
+                            .with_note("unsafe binders are the only valid output of wrap")
+                            .emit();
+                        Ty::new_error(self.tcx, guar)
+                    }
+                };
+
+                self.check_expr_has_type_or_error(inner_expr, hint_ty, |_| {});
+
+                binder_ty
+            }
+            hir::UnsafeBinderCastKind::Unwrap => {
+                let ascribed_ty =
+                    hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
+                let hint_ty = ascribed_ty.unwrap_or_else(|| self.next_ty_var(inner_expr.span));
+                // FIXME(unsafe_binders): coerce here if needed?
+                let binder_ty = self.check_expr_has_type_or_error(inner_expr, hint_ty, |_| {});
+
+                // Unwrap the binder. This will be ambiguous if it's an infer var, and will error
+                // if it's not an unsafe binder.
+                let binder_ty = self.structurally_resolve_type(inner_expr.span, binder_ty);
+                match *binder_ty.kind() {
+                    ty::UnsafeBinder(binder) => self.instantiate_binder_with_fresh_vars(
+                        inner_expr.span,
+                        infer::BoundRegionConversionTime::HigherRankedType,
+                        binder.into(),
+                    ),
+                    ty::Error(e) => Ty::new_error(self.tcx, e),
+                    _ => {
+                        let guar = self
+                            .dcx()
+                            .struct_span_err(
+                                hir_ty.map_or(inner_expr.span, |hir_ty| hir_ty.span),
+                                format!(
+                                    "expected unsafe binder, found {} as input of \
+                                    `unwrap_binder!()`",
+                                    binder_ty.sort_string(self.tcx)
+                                ),
+                            )
+                            .with_note("only an unsafe binder type can be unwrapped")
+                            .emit();
+                        Ty::new_error(self.tcx, guar)
+                    }
+                }
+            }
+        }
     }
 
     fn check_expr_array(
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index fe66d306ceb..c47f27e871f 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -441,6 +441,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
             | ty::FnDef(..)
             | ty::FnPtr(..)
             | ty::Dynamic(..)
+            | ty::UnsafeBinder(_)
             | ty::Never
             | ty::Tuple(..)
             | ty::Alias(..)
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index c0371b1f606..ef9aa11ef7b 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1284,6 +1284,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
+            ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+
             ty::Param(..)
             | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
             | ty::Infer(..)
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 977e62becf1..d26c007d227 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -471,7 +471,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
             | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
             | ty::Never
-            | ty::Tuple(_) => {
+            | ty::Tuple(_)
+            | ty::UnsafeBinder(_) => {
                 let simp = ty::fast_reject::simplify_type(
                     tcx,
                     self_ty,
@@ -2295,6 +2296,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     Ref,
                     FnDef,
                     FnPtr,
+                    UnsafeBinder,
                     Placeholder,
                     Coroutine,
                     CoroutineWitness,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 4a82af32559..714094db053 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -191,6 +191,7 @@ impl<'tcx> Ty<'tcx> {
                 _ => "fn item".into(),
             },
             ty::FnPtr(..) => "fn pointer".into(),
+            ty::UnsafeBinder(_) => "unsafe binder".into(),
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) | ty::CoroutineClosure(..) => "closure".into(),
             ty::Coroutine(def_id, ..) => {
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 04d03187541..0af57f636aa 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -253,6 +253,12 @@ impl FlagComputation {
             &ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
                 computation.add_tys(sig_tys.inputs_and_output);
             }),
+
+            &ty::UnsafeBinder(bound_ty) => {
+                self.bound_computation(bound_ty.into(), |computation, ty| {
+                    computation.add_ty(ty);
+                })
+            }
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 367b0c07f9b..6e6da6de749 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -816,6 +816,11 @@ where
                     bug!("TyAndLayout::field({:?}): not applicable", this)
                 }
 
+                ty::UnsafeBinder(bound_ty) => {
+                    let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
+                    field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i)
+                }
+
                 // Potentially-wide pointers.
                 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                     assert!(i < this.fields.count());
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index cc746746760..b0150bc1192 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -291,6 +291,7 @@ fn characteristic_def_id_of_type_cached<'a>(
         | ty::Uint(_)
         | ty::Str
         | ty::FnPtr(..)
+        | ty::UnsafeBinder(_)
         | ty::Alias(..)
         | ty::Placeholder(..)
         | ty::Param(_)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index a089eac5d7e..8e89331ef03 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -695,6 +695,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 }
             }
             ty::FnPtr(ref sig_tys, hdr) => p!(print(sig_tys.with(hdr))),
+            ty::UnsafeBinder(ref bound_ty) => {
+                // FIXME(unsafe_binders): Make this print `unsafe<>` rather than `for<>`.
+                self.wrap_binder(bound_ty, |ty, cx| cx.pretty_print_type(*ty))?;
+            }
             ty::Infer(infer_ty) => {
                 if self.should_print_verbose() {
                     p!(write("{:?}", ty.kind()));
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index f38454ceac0..68cb56f3583 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -393,6 +393,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
             ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?),
             ty::FnDef(def_id, args) => ty::FnDef(def_id, args.try_fold_with(folder)?),
             ty::FnPtr(sig_tys, hdr) => ty::FnPtr(sig_tys.try_fold_with(folder)?, hdr),
+            ty::UnsafeBinder(f) => ty::UnsafeBinder(f.try_fold_with(folder)?),
             ty::Ref(r, ty, mutbl) => {
                 ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl)
             }
@@ -443,6 +444,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
             ty::Tuple(ts) => ts.visit_with(visitor),
             ty::FnDef(_, args) => args.visit_with(visitor),
             ty::FnPtr(ref sig_tys, _) => sig_tys.visit_with(visitor),
+            ty::UnsafeBinder(ref f) => f.visit_with(visitor),
             ty::Ref(r, ty, _) => {
                 try_visit!(r.visit_with(visitor));
                 ty.visit_with(visitor)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 045c483d6a5..92b3632c8ac 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -674,6 +674,11 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    pub fn new_unsafe_binder(tcx: TyCtxt<'tcx>, b: Binder<'tcx, Ty<'tcx>>) -> Ty<'tcx> {
+        Ty::new(tcx, UnsafeBinder(b.into()))
+    }
+
+    #[inline]
     pub fn new_dynamic(
         tcx: TyCtxt<'tcx>,
         obj: &'tcx List<ty::PolyExistentialPredicate<'tcx>>,
@@ -962,6 +967,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         Ty::new_pat(interner, ty, pat)
     }
 
+    fn new_unsafe_binder(interner: TyCtxt<'tcx>, ty: ty::Binder<'tcx, Ty<'tcx>>) -> Self {
+        Ty::new_unsafe_binder(interner, ty)
+    }
+
     fn new_unit(interner: TyCtxt<'tcx>) -> Self {
         interner.types.unit
     }
@@ -1480,6 +1489,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Tuple(_)
+            | ty::UnsafeBinder(_)
             | ty::Error(_)
             | ty::Infer(IntVar(_) | FloatVar(_)) => tcx.types.u8,
 
@@ -1659,6 +1669,8 @@ impl<'tcx> Ty<'tcx> {
             // metadata of `tail`.
             ty::Param(_) | ty::Alias(..) => Err(tail),
 
+            | ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+
             ty::Infer(ty::TyVar(_))
             | ty::Pat(..)
             | ty::Bound(..)
@@ -1819,6 +1831,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Float(_)
             | ty::FnDef(..)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::RawPtr(..)
             | ty::Char
             | ty::Ref(..)
@@ -1898,6 +1911,8 @@ impl<'tcx> Ty<'tcx> {
             // Might be, but not "trivial" so just giving the safe answer.
             ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) => false,
 
+            ty::UnsafeBinder(_) => false,
+
             // Needs normalization or revealing to determine, so no is the safe answer.
             ty::Alias(..) => false,
 
@@ -1976,7 +1991,8 @@ impl<'tcx> Ty<'tcx> {
             | Coroutine(_, _)
             | CoroutineWitness(..)
             | Never
-            | Tuple(_) => true,
+            | Tuple(_)
+            | UnsafeBinder(_) => true,
             Error(_) | Infer(_) | Alias(_, _) | Param(_) | Bound(_, _) | Placeholder(_) => false,
         }
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index fc3530e3dde..ab8285f87d6 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1241,6 +1241,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Foreign(_)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
+            | ty::UnsafeBinder(_)
             | ty::Infer(_)
             | ty::Alias(..)
             | ty::Param(_)
@@ -1281,6 +1282,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Foreign(_)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
+            | ty::UnsafeBinder(_)
             | ty::Infer(_)
             | ty::Alias(..)
             | ty::Param(_)
@@ -1322,6 +1324,9 @@ impl<'tcx> Ty<'tcx> {
             | ty::Infer(ty::FreshIntTy(_))
             | ty::Infer(ty::FreshFloatTy(_)) => AsyncDropGlueMorphology::Noop,
 
+            // FIXME(unsafe_binders):
+            ty::UnsafeBinder(_) => todo!(),
+
             ty::Tuple(tys) if tys.is_empty() => AsyncDropGlueMorphology::Noop,
             ty::Adt(adt_def, _) if adt_def.is_manually_drop() => AsyncDropGlueMorphology::Noop,
 
@@ -1522,7 +1527,7 @@ impl<'tcx> Ty<'tcx> {
                 false
             }
 
-            ty::Foreign(_) | ty::CoroutineWitness(..) | ty::Error(_) => false,
+            ty::Foreign(_) | ty::CoroutineWitness(..) | ty::Error(_) | ty::UnsafeBinder(_) => false,
         }
     }
 
@@ -1681,7 +1686,8 @@ pub fn needs_drop_components_with_async<'tcx>(
         | ty::Closure(..)
         | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
-        | ty::CoroutineWitness(..) => Ok(smallvec![ty]),
+        | ty::CoroutineWitness(..)
+        | ty::UnsafeBinder(_) => Ok(smallvec![ty]),
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index a93a146ec7c..2dcba8c2f82 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -194,6 +194,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                     sig_tys.skip_binder().inputs_and_output.iter().rev().map(|ty| ty.into()),
                 );
             }
+            ty::UnsafeBinder(bound_ty) => {
+                stack.push(bound_ty.skip_binder().into());
+            }
         },
         GenericArgKind::Lifetime(_) => {}
         GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 0880364bfca..d1b3a389e9e 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -161,6 +161,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                     | ty::CoroutineWitness(..)
                     | ty::Never
                     | ty::Tuple(_)
+                    | ty::UnsafeBinder(_)
                     | ty::Alias(_, _)
                     | ty::Param(_)
                     | ty::Bound(_, _)
@@ -200,6 +201,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                     | ty::Dynamic(_, _, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
+                    | ty::UnsafeBinder(_)
                     | ty::Alias(_, _)
                     | ty::Param(_)
                     | ty::Bound(_, _)
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 711cf2edc46..51af77778af 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -944,7 +944,8 @@ fn try_write_constant<'tcx>(
         | ty::Closure(..)
         | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
-        | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"),
+        | ty::Dynamic(..)
+        | ty::UnsafeBinder(_) => throw_machine_stop_str!("unsupported type"),
 
         ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(),
     }
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
index 7fb421dea0c..e5a183bc75c 100644
--- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -285,7 +285,9 @@ fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
         | ty::Placeholder(_)
         | ty::Infer(_)
         | ty::Slice(_)
-        | ty::Array(_, _) => None,
+        | ty::Array(_, _)
+        | ty::UnsafeBinder(_) => None,
+
         ty::Adt(adt_def, _) => {
             let did = adt_def.did();
             let try_local_did_span = |did: DefId| {
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 2f7301d8fe5..8a54a4ece98 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -378,6 +378,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             | ty::Pat(_, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs
index 2461ef0c0df..408742747c2 100644
--- a/compiler/rustc_next_trait_solver/src/coherence.rs
+++ b/compiler/rustc_next_trait_solver/src/coherence.rs
@@ -339,7 +339,9 @@ where
             | ty::Slice(..)
             | ty::RawPtr(..)
             | ty::Never
-            | ty::Tuple(..) => self.found_non_local_ty(ty),
+            | ty::Tuple(..)
+            // FIXME(unsafe_binders): Non-local?
+            | ty::UnsafeBinder(_) => self.found_non_local_ty(ty),
 
             ty::Param(..) => panic!("unexpected ty param"),
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 02f6439b77f..63432dc199b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -545,6 +545,7 @@ where
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::Dynamic(..)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
@@ -634,6 +635,7 @@ where
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::Alias(..)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 05ce61bc067..7da4f5e0107 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -83,6 +83,8 @@ where
             .map(|bty| bty.instantiate(cx, args))
             .collect()),
 
+        ty::UnsafeBinder(bound_ty) => Ok(vec![bound_ty.into()]),
+
         // For `PhantomData<T>`, we pass `T`.
         ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]),
 
@@ -144,6 +146,8 @@ where
             panic!("unexpected type `{ty:?}`")
         }
 
+        ty::UnsafeBinder(bound_ty) => Ok(vec![bound_ty.into()]),
+
         // impl Sized for ()
         // impl Sized for (T1, T2, .., Tn) where Tn: Sized if n >= 1
         ty::Tuple(tys) => Ok(tys.last().map_or_else(Vec::new, |ty| vec![ty::Binder::dummy(ty)])),
@@ -239,6 +243,8 @@ where
             }
         },
 
+        ty::UnsafeBinder(_) => Err(NoSolution),
+
         // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .cx()
@@ -374,6 +380,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
         | ty::Never
         | ty::Tuple(_)
         | ty::Pat(_, _)
+        | ty::UnsafeBinder(_)
         | ty::Alias(_, _)
         | ty::Param(_)
         | ty::Placeholder(..)
@@ -544,6 +551,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
         | ty::Coroutine(_, _)
         | ty::CoroutineWitness(..)
         | ty::Never
+        | ty::UnsafeBinder(_)
         | ty::Tuple(_)
         | ty::Alias(_, _)
         | ty::Param(_)
@@ -694,7 +702,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
         | ty::Param(_)
         | ty::Placeholder(..)
         | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
-        | ty::Error(_) => return Err(NoSolution),
+        | ty::Error(_)
+        | ty::UnsafeBinder(_) => return Err(NoSolution),
 
         ty::Bound(..)
         | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
@@ -764,6 +773,10 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
         | ty::Coroutine(_, _)
         | ty::CoroutineWitness(_, _) => Err(NoSolution),
 
+        // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop`
+        // if their inner type implements it.
+        ty::UnsafeBinder(_) => Err(NoSolution),
+
         ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => {
             Err(NoSolution)
         }
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index b8867192225..f5ecfea5408 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -619,6 +619,11 @@ where
                     Some(tail_ty) => Ty::new_projection(cx, metadata_def_id, [tail_ty]),
                 },
 
+                ty::UnsafeBinder(_) => {
+                    // FIXME(unsafe_binder): Figure out how to handle pointee for unsafe binders.
+                    todo!()
+                }
+
                 ty::Infer(
                     ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
                 )
@@ -822,6 +827,11 @@ where
             | ty::Tuple(_)
             | ty::Error(_) => self_ty.discriminant_ty(ecx.cx()),
 
+            ty::UnsafeBinder(_) => {
+                // FIXME(unsafe_binders): instantiate this with placeholders?? i guess??
+                todo!("discr subgoal...")
+            }
+
             // We do not call `Ty::discriminant_ty` on alias, param, or placeholder
             // types, which return `<self_ty as DiscriminantKind>::Discriminant`
             // (or ICE in the case of placeholders). Projecting a type to itself
@@ -869,6 +879,11 @@ where
             | ty::Tuple(_)
             | ty::Error(_) => self_ty.async_destructor_ty(ecx.cx()),
 
+            ty::UnsafeBinder(_) => {
+                // FIXME(unsafe_binders): Instantiate the binder with placeholders I guess.
+                todo!()
+            }
+
             // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder
             // types, which return `<self_ty as AsyncDestruct>::AsyncDestructor`
             // (or ICE in the case of placeholders). Projecting a type to itself
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 886cdec0345..d68fca60829 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -1100,7 +1100,8 @@ where
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Adt(_, _) => {
+            | ty::Adt(_, _)
+            | ty::UnsafeBinder(_) => {
                 let mut disqualifying_impl = None;
                 self.cx().for_each_relevant_impl(
                     goal.predicate.def_id(),
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 009d817a1a9..ae991e3ce40 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -415,6 +415,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
+            | ty::UnsafeBinder(_)
             | ty::Alias(_, _)
             | ty::Param(_)
             | ty::Error(_) => ConstructorSet::Unlistable,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index c50c9007a01..9ae2d981ab0 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -285,6 +285,7 @@ where
             | ty::Ref(..)
             | ty::Pat(..)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::Param(..)
             | ty::Bound(..)
             | ty::Error(_)
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 34e1c31683a..895259d52a7 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -621,6 +621,11 @@ pub(crate) fn encode_ty<'tcx>(
             typeid.push_str(&s);
         }
 
+        // FIXME(unsafe_binders): Implement this.
+        ty::UnsafeBinder(_) => {
+            todo!()
+        }
+
         // Trait types
         ty::Dynamic(predicates, region, kind) => {
             // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 9c01bd04353..9c6186d6882 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -64,7 +64,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
             | ty::Pat(..)
             | ty::Slice(..)
             | ty::Str
-            | ty::Tuple(..) => t.super_fold_with(self),
+            | ty::Tuple(..)
+            | ty::UnsafeBinder(_) => t.super_fold_with(self),
 
             ty::Bool => {
                 if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index a4f61313001..e15dad78c69 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -356,6 +356,8 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
             ty::FnPtr(sig_tys, hdr) => {
                 TyKind::RigidTy(RigidTy::FnPtr(sig_tys.with(*hdr).stable(tables)))
             }
+            // FIXME(unsafe_binders):
+            ty::UnsafeBinder(_) => todo!(),
             ty::Dynamic(existential_predicates, region, dyn_kind) => {
                 TyKind::RigidTy(RigidTy::Dynamic(
                     existential_predicates
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 123e4b1f01f..65e515c0c2d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2149,6 +2149,7 @@ symbols! {
         unwrap,
         unwrap_binder,
         unwrap_or,
+        unwrap_unsafe_binder,
         use_extern_macros,
         use_nested_groups,
         used,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index a801b3e53a1..0ca47eba5e8 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -466,6 +466,9 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 })?;
             }
 
+            // FIXME(unsafe_binder):
+            ty::UnsafeBinder(..) => todo!(),
+
             ty::Dynamic(predicates, r, kind) => {
                 self.push(match kind {
                     ty::Dyn => "D",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index d41f8f46c17..885b606326c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1532,6 +1532,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 ty::CoroutineWitness(..) => Some(20),
                 ty::CoroutineClosure(..) => Some(21),
                 ty::Pat(..) => Some(22),
+                ty::UnsafeBinder(..) => Some(23),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 4bccd3450bc..54407d17dcf 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1047,6 +1047,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         // Integers and floats always have `u8` as their discriminant.
                         | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
 
+                        ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+
                         // type parameters, opaques, and unnormalized projections don't have
                         // a known discriminant and may need to be normalized further or rely
                         // on param env for discriminant projections
@@ -1072,6 +1074,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Ref(..)
                         | ty::FnDef(..)
                         | ty::FnPtr(..)
+                        | ty::UnsafeBinder(_)
                         | ty::Dynamic(..)
                         | ty::Closure(..)
                         | ty::CoroutineClosure(..)
@@ -1163,6 +1166,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                             true
                         }
 
+                        ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+
                         // FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
                         ty::Param(_)
                         | ty::Alias(..)
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 1d3e8d43af7..4004e354dc1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -83,7 +83,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Placeholder(..)
         | ty::Infer(_)
         | ty::Bound(..)
-        | ty::Coroutine(..) => false,
+        | ty::Coroutine(..)
+        | ty::UnsafeBinder(_) => false,
     }
 }
 
@@ -336,6 +337,11 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             constraints.dtorck_types.push(ty);
         }
 
+        // Can't instantiate binder here.
+        ty::UnsafeBinder(_) => {
+            constraints.dtorck_types.push(ty);
+        }
+
         ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
             // By the time this code runs, all type variables ought to
             // be fully resolved.
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 5e27fd43789..d6ac4baf8ad 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -619,7 +619,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 continue;
             }
 
-            match obligation.self_ty().skip_binder().kind() {
+            let self_ty = obligation.self_ty().skip_binder();
+            match self_ty.kind() {
                 // Fast path to avoid evaluating an obligation that trivially holds.
                 // There may be more bounds, but these are checked by the regular path.
                 ty::FnPtr(..) => return false,
@@ -651,6 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::CoroutineClosure(..)
                 | ty::Coroutine(_, _)
                 | ty::CoroutineWitness(..)
+                | ty::UnsafeBinder(_)
                 | ty::Never
                 | ty::Tuple(_)
                 | ty::Error(_) => return true,
@@ -794,7 +796,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Coroutine(..)
                 | ty::Never
                 | ty::Tuple(_)
-                | ty::CoroutineWitness(..) => {
+                | ty::CoroutineWitness(..)
+                | ty::UnsafeBinder(_) => {
                     // Only consider auto impls of unsafe traits when there are
                     // no unsafe fields.
                     if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() {
@@ -1176,6 +1179,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::FnDef(_, _)
             | ty::Pat(_, _)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
@@ -1220,6 +1224,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
+            | ty::UnsafeBinder(_)
             | ty::Never
             | ty::Tuple(..)
             | ty::Alias(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0462b1d9ee7..7857ed95cc7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2095,6 +2095,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 }
             }
 
+            // FIXME(unsafe_binders): This binder needs to be squashed
+            ty::UnsafeBinder(binder_ty) => Where(binder_ty.map_bound(|ty| vec![ty])),
+
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None,
             ty::Infer(ty::TyVar(_)) => Ambiguous,
 
@@ -2133,6 +2136,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 None
             }
 
+            // FIXME(unsafe_binder): Should we conditionally
+            // (i.e. universally) implement copy/clone?
+            ty::UnsafeBinder(_) => None,
+
             ty::Dynamic(..)
             | ty::Str
             | ty::Slice(..)
@@ -2285,6 +2292,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Never
             | ty::Char => ty::Binder::dummy(Vec::new()),
 
+            // FIXME(unsafe_binders): Squash the double binder for now, I guess.
+            ty::UnsafeBinder(_) => return Err(SelectionError::Unimplemented),
+
             // Treat this like `struct str([u8]);`
             ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]),
 
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index c95b1641d1f..9d32eb05386 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -828,6 +828,9 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // Let the visitor iterate into the argument/return
                 // types appearing in the fn signature.
             }
+            ty::UnsafeBinder(_) => {
+                // FIXME(unsafe_binders): We should also recurse into the binder here.
+            }
 
             ty::Dynamic(data, r, _) => {
                 // WfObject
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index eb30169a7d9..fc76a86f797 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -49,7 +49,8 @@ fn resolve_instance_raw<'tcx>(
                     | ty::Adt(..)
                     | ty::Dynamic(..)
                     | ty::Array(..)
-                    | ty::Slice(..) => {}
+                    | ty::Slice(..)
+                    | ty::UnsafeBinder(..) => {}
                     // Drop shims can only be built from ADTs.
                     _ => return Ok(None),
                 }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index a3b2ed07d4b..9f138cf1275 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -666,6 +666,11 @@ fn layout_of_uncached<'tcx>(
             tcx.mk_layout(layout)
         }
 
+        ty::UnsafeBinder(bound_ty) => {
+            let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
+            cx.layout_of(ty)?.layout
+        }
+
         // Types with no meaningful known layout.
         ty::Alias(..) => {
             // NOTE(eddyb) `layout_of` query should've normalized these away,
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 1c85eb2a861..80de7e20951 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -202,6 +202,11 @@ where
                         }
                     }
 
+                    ty::UnsafeBinder(bound_ty) => {
+                        let ty = self.tcx.instantiate_bound_regions_with_erased(bound_ty.into());
+                        queue_type(self, ty);
+                    }
+
                     _ if tcx.type_is_copy_modulo_regions(self.typing_env, component) => {}
 
                     ty::Closure(_, args) => {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 774f0660258..7eed32e3a33 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -37,6 +37,8 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'
         | Never
         | Dynamic(_, _, ty::DynStar) => None,
 
+        UnsafeBinder(_) => todo!(),
+
         // these are never sized
         Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty),
 
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index c06a578d8ec..47447af2215 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -6,8 +6,6 @@ use std::ops::{ControlFlow, Deref};
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
-#[cfg(feature = "nightly")]
-use rustc_serialize::Decodable;
 use tracing::instrument;
 
 use crate::data_structures::SsoHashSet;
@@ -69,14 +67,14 @@ macro_rules! impl_binder_encode_decode {
                     self.as_ref().skip_binder().encode(e);
                 }
             }
-            impl<I: Interner, D: crate::TyDecoder<I = I>> Decodable<D> for ty::Binder<I, $t>
+            impl<I: Interner, D: crate::TyDecoder<I = I>> rustc_serialize::Decodable<D> for ty::Binder<I, $t>
             where
                 $t: TypeVisitable<I> + rustc_serialize::Decodable<D>,
                 I::BoundVarKinds: rustc_serialize::Decodable<D>,
             {
                 fn decode(decoder: &mut D) -> Self {
-                    let bound_vars = Decodable::decode(decoder);
-                    ty::Binder::bind_with_vars(<$t>::decode(decoder), bound_vars)
+                    let bound_vars = rustc_serialize::Decodable::decode(decoder);
+                    ty::Binder::bind_with_vars(rustc_serialize::Decodable::decode(decoder), bound_vars)
                 }
             }
         )*
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs
index 81c8a7d4bfa..9b3ff14d507 100644
--- a/compiler/rustc_type_ir/src/fast_reject.rs
+++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -41,6 +41,7 @@ pub enum SimplifiedType<DefId> {
     Coroutine(DefId),
     CoroutineWitness(DefId),
     Function(usize),
+    UnsafeBinder,
     Placeholder,
     Error,
 }
@@ -138,6 +139,7 @@ pub fn simplify_type<I: Interner>(
         ty::FnPtr(sig_tys, _hdr) => {
             Some(SimplifiedType::Function(sig_tys.skip_binder().inputs().len()))
         }
+        ty::UnsafeBinder(_) => Some(SimplifiedType::UnsafeBinder),
         ty::Placeholder(..) => Some(SimplifiedType::Placeholder),
         ty::Param(_) => match treat_params {
             TreatParams::AsRigid => Some(SimplifiedType::Placeholder),
@@ -290,7 +292,8 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Foreign(_)
-            | ty::Placeholder(_) => {}
+            | ty::Placeholder(_)
+            | ty::UnsafeBinder(_) => {}
         };
 
         // The type system needs to support exponentially large types
@@ -447,6 +450,13 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
                 matches!(rhs.kind(), ty::Pat(rhs_ty, _) if self.types_may_unify_inner(lhs_ty, rhs_ty, depth))
             }
 
+            ty::UnsafeBinder(lhs_ty) => match rhs.kind() {
+                ty::UnsafeBinder(rhs_ty) => {
+                    self.types_may_unify(lhs_ty.skip_binder(), rhs_ty.skip_binder())
+                }
+                _ => false,
+            },
+
             ty::Error(..) => true,
         }
     }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 2db40accda3..872cf668018 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -112,6 +112,8 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self;
 
+    fn new_unsafe_binder(interner: I, ty: ty::Binder<I, I::Ty>) -> Self;
+
     fn tuple_fields(self) -> I::Tys;
 
     fn to_opt_closure_kind(self) -> Option<ty::ClosureKind>;
@@ -185,6 +187,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(_, _)
             | ty::CoroutineClosure(_, _)
diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs
index 0e94e989b97..c26e211a794 100644
--- a/compiler/rustc_type_ir/src/outlives.rs
+++ b/compiler/rustc_type_ir/src/outlives.rs
@@ -202,6 +202,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnPtr(..)
+            | ty::UnsafeBinder(_)
             | ty::Dynamic(_, _, _)
             | ty::Tuple(_) => {
                 ty.super_visit_with(self);
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index 0b013b2017f..e628b66d2f0 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -549,6 +549,10 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
             Ok(Ty::new_pat(cx, ty, pat))
         }
 
+        (ty::UnsafeBinder(a_binder), ty::UnsafeBinder(b_binder)) => {
+            Ok(Ty::new_unsafe_binder(cx, relation.binders(*a_binder, *b_binder)?))
+        }
+
         _ => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
     }
 }
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 033fcdb6c03..52e4fa19cb0 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -1,4 +1,5 @@
 use std::fmt;
+use std::ops::Deref;
 
 use derive_where::derive_where;
 use rustc_ast_ir::Mutability;
@@ -13,6 +14,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
 use self::TyKind::*;
 pub use self::closure::*;
 use crate::inherent::*;
+use crate::visit::TypeVisitable;
 use crate::{self as ty, DebruijnIndex, Interner};
 
 mod closure;
@@ -150,6 +152,13 @@ pub enum TyKind<I: Interner> {
     /// worth the mild inconvenience.
     FnPtr(ty::Binder<I, FnSigTys<I>>, FnHeader<I>),
 
+    /// An unsafe binder type.
+    ///
+    /// A higher-ranked type used to represent a type which has had some of its
+    /// lifetimes erased. This can be used to represent types in positions where
+    /// a lifetime is literally inexpressible, such as self-referential types.
+    UnsafeBinder(UnsafeBinderInner<I>),
+
     /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
     Dynamic(I::BoundExistentialPredicates, I::Region, DynKind),
 
@@ -287,6 +296,8 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
             Ref(r, t, m) => write!(f, "&{:?} {}{:?}", r, m.prefix_str(), t),
             FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&s).finish(),
             FnPtr(sig_tys, hdr) => write!(f, "{:?}", sig_tys.with(*hdr)),
+            // FIXME(unsafe_binder): print this like `unsafe<'a> T<'a>`.
+            UnsafeBinder(binder) => write!(f, "{:?}", binder),
             Dynamic(p, r, repr) => match repr {
                 DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"),
                 DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"),
@@ -964,6 +975,66 @@ impl<I: Interner> fmt::Debug for FnSig<I> {
     }
 }
 
+// FIXME: this is a distinct type because we need to define `Encode`/`Decode`
+// impls in this crate for `Binder<I, I::Ty>`.
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+pub struct UnsafeBinderInner<I: Interner>(ty::Binder<I, I::Ty>);
+
+impl<I: Interner> From<ty::Binder<I, I::Ty>> for UnsafeBinderInner<I> {
+    fn from(value: ty::Binder<I, I::Ty>) -> Self {
+        UnsafeBinderInner(value)
+    }
+}
+
+impl<I: Interner> From<UnsafeBinderInner<I>> for ty::Binder<I, I::Ty> {
+    fn from(value: UnsafeBinderInner<I>) -> Self {
+        value.0
+    }
+}
+
+impl<I: Interner> fmt::Debug for UnsafeBinderInner<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl<I: Interner> Deref for UnsafeBinderInner<I> {
+    type Target = ty::Binder<I, I::Ty>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl<I: Interner, E: crate::TyEncoder<I = I>> rustc_serialize::Encodable<E> for UnsafeBinderInner<I>
+where
+    I::Ty: rustc_serialize::Encodable<E>,
+    I::BoundVarKinds: rustc_serialize::Encodable<E>,
+{
+    fn encode(&self, e: &mut E) {
+        self.bound_vars().encode(e);
+        self.as_ref().skip_binder().encode(e);
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl<I: Interner, D: crate::TyDecoder<I = I>> rustc_serialize::Decodable<D> for UnsafeBinderInner<I>
+where
+    I::Ty: TypeVisitable<I> + rustc_serialize::Decodable<D>,
+    I::BoundVarKinds: rustc_serialize::Decodable<D>,
+{
+    fn decode(decoder: &mut D) -> Self {
+        let bound_vars = rustc_serialize::Decodable::decode(decoder);
+        UnsafeBinderInner(ty::Binder::bind_with_vars(
+            rustc_serialize::Decodable::decode(decoder),
+            bound_vars,
+        ))
+    }
+}
+
 // This is just a `FnSig` without the `FnHeader` fields.
 #[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9d0c0f687c7..4d46f0e75c8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2255,12 +2255,14 @@ pub(crate) fn clean_middle_ty<'tcx>(
             }
         }
 
+        ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
         ty::Closure(..) => panic!("Closure"),
         ty::CoroutineClosure(..) => panic!("CoroutineClosure"),
         ty::Coroutine(..) => panic!("Coroutine"),
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::CoroutineWitness(..) => panic!("CoroutineWitness"),
         ty::Infer(..) => panic!("Infer"),
+
         ty::Error(_) => FatalError.raise(),
     }
 }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index c9d1ceb0a91..3c1d0c35bef 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -559,6 +559,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Dynamic(..)
+            | ty::UnsafeBinder(_)
             | ty::Param(_)
             | ty::Bound(..)
             | ty::Placeholder(_)
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index e3959903fdd..821312a9e40 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -877,7 +877,8 @@ impl TyCoercionStability {
                 | ty::CoroutineClosure(..)
                 | ty::Never
                 | ty::Tuple(_)
-                | ty::Alias(ty::Projection, _) => Self::Deref,
+                | ty::Alias(ty::Projection, _)
+                | ty::UnsafeBinder(_) => Self::Deref,
             };
         }
     }
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 71499b1293a..afceeec2272 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -677,6 +677,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             ExprKind::Type(e, _) => {
                 helper(typeck, consume, e, f)?;
             },
+            ExprKind::UnsafeBinderCast(_, e, _) => {
+                helper(typeck, consume, e, f)?;
+            },
 
             // Either drops temporaries, jumps out of the current expression, or has no sub expression.
             ExprKind::DropTemps(_)
@@ -694,7 +697,6 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             | ExprKind::Continue(_)
             | ExprKind::InlineAsm(_)
             | ExprKind::OffsetOf(..)
-            | ExprKind::UnsafeBinderCast(..)
             | ExprKind::Err(_) => (),
         }
         ControlFlow::Continue(())
diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs
index d9b61e73621..c51884451e5 100644
--- a/tests/debuginfo/function-names.rs
+++ b/tests/debuginfo/function-names.rs
@@ -37,7 +37,7 @@
 // Const generic parameter
 // gdb-command:info functions -q function_names::const_generic_fn.*
 // gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
-// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#a70c39591cb5f53d}>();
+// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#ffa3db4ca1d52dce}>();
 // gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
 // gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
 
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
index f77b318039d..91998a8ec45 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
@@ -13,34 +13,8 @@ fn main() {
     let kind = TyKind::Bool; //~ ERROR usage of `ty::TyKind::<kind>`
 
     match kind {
-        TyKind::Bool => (),                 //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Char => (),                 //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Int(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Uint(..) => (),             //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Float(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Adt(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Foreign(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Str => (),                  //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Array(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Pat(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Slice(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::RawPtr(..) => (),           //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Ref(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::FnDef(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::FnPtr(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Dynamic(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Closure(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::CoroutineClosure(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Coroutine(..) => (),        //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::CoroutineWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Never => (),                //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Tuple(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Alias(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Param(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Bound(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Placeholder(..) => (),      //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Infer(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Error(_) => (),             //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Bool => {},                 //~ ERROR usage of `ty::TyKind::<kind>`
+        _ => {}
     }
 
     if let ty::Int(int_ty) = kind {}
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
index 53bf5cb1a82..19a73b36bfe 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
@@ -13,179 +13,17 @@ LL | #[deny(rustc::usage_of_ty_tykind)]
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:16:9
    |
-LL |         TyKind::Bool => (),
+LL |         TyKind::Bool => {},
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:17:9
-   |
-LL |         TyKind::Char => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:18:9
-   |
-LL |         TyKind::Int(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:19:9
-   |
-LL |         TyKind::Uint(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:20:9
-   |
-LL |         TyKind::Float(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:21:9
-   |
-LL |         TyKind::Adt(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:22:9
-   |
-LL |         TyKind::Foreign(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:23:9
-   |
-LL |         TyKind::Str => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:24:9
-   |
-LL |         TyKind::Array(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:25:9
-   |
-LL |         TyKind::Pat(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:26:9
-   |
-LL |         TyKind::Slice(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:27:9
-   |
-LL |         TyKind::RawPtr(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:28:9
-   |
-LL |         TyKind::Ref(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:29:9
-   |
-LL |         TyKind::FnDef(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:30:9
-   |
-LL |         TyKind::FnPtr(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:31:9
-   |
-LL |         TyKind::Dynamic(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:32:9
-   |
-LL |         TyKind::Closure(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:33:9
-   |
-LL |         TyKind::CoroutineClosure(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:34:9
-   |
-LL |         TyKind::Coroutine(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:35:9
-   |
-LL |         TyKind::CoroutineWitness(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:36:9
-   |
-LL |         TyKind::Never => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:37:9
-   |
-LL |         TyKind::Tuple(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:38:9
-   |
-LL |         TyKind::Alias(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:39:9
-   |
-LL |         TyKind::Param(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:40:9
-   |
-LL |         TyKind::Bound(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:41:9
-   |
-LL |         TyKind::Placeholder(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:42:9
-   |
-LL |         TyKind::Infer(..) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:43:9
-   |
-LL |         TyKind::Error(_) => (),
-   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:48:12
+  --> $DIR/ty_tykind_usage.rs:22:12
    |
 LL |     if let TyKind::Int(int_ty) = kind {}
    |            ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:50:24
+  --> $DIR/ty_tykind_usage.rs:24:24
    |
 LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    |                        ^^^^^^^^^^
@@ -193,7 +31,7 @@ LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:52:37
+  --> $DIR/ty_tykind_usage.rs:26:37
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                     ^^^^^^^^^^^
@@ -201,7 +39,7 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:52:53
+  --> $DIR/ty_tykind_usage.rs:26:53
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                                     ^^^^^^^^^^^
@@ -209,12 +47,12 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:55:9
+  --> $DIR/ty_tykind_usage.rs:29:9
    |
 LL |         IrTyKind::Bool
    |         --------^^^^^^
    |         |
    |         help: try using `ty::<kind>` directly: `ty`
 
-error: aborting due to 34 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-auto-traits.rs b/tests/ui/feature-gates/feature-gate-auto-traits.rs
index 80cfa9cee89..aab9e784fe9 100644
--- a/tests/ui/feature-gates/feature-gate-auto-traits.rs
+++ b/tests/ui/feature-gates/feature-gate-auto-traits.rs
@@ -7,6 +7,6 @@ auto trait AutoDummyTrait {}
 //~^ ERROR auto traits are experimental and possibly buggy
 
 impl !AutoDummyTrait for DummyStruct {}
-//~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now
+//~^ ERROR negative trait bounds are not fully implemented; use marker types for now
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-auto-traits.stderr b/tests/ui/feature-gates/feature-gate-auto-traits.stderr
index 139229ca809..8fa5168b2d0 100644
--- a/tests/ui/feature-gates/feature-gate-auto-traits.stderr
+++ b/tests/ui/feature-gates/feature-gate-auto-traits.stderr
@@ -8,7 +8,7 @@ LL | auto trait AutoDummyTrait {}
    = help: add `#![feature(auto_traits)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now
+error[E0658]: negative trait bounds are not fully implemented; use marker types for now
   --> $DIR/feature-gate-auto-traits.rs:9:6
    |
 LL | impl !AutoDummyTrait for DummyStruct {}
diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index 6ce0ae09195..2f26c0cf0d3 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17had874e876c8b1028E)
+error: symbol-name(_ZN5basic4main17h144191e1523a280eE)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::had874e876c8b1028)
+error: demangling(basic::main::h144191e1523a280e)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index cc4eec470fb..cc79cc8b516 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17haf0d0ad2255e29c6E)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h71f988fda3b6b180E)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::haf0d0ad2255e29c6)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h71f988fda3b6b180)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/tests/ui/traits/negative-impls/feature-gate-negative_impls.rs b/tests/ui/traits/negative-impls/feature-gate-negative_impls.rs
index 683fd6db6f2..8d3f6ff6d78 100644
--- a/tests/ui/traits/negative-impls/feature-gate-negative_impls.rs
+++ b/tests/ui/traits/negative-impls/feature-gate-negative_impls.rs
@@ -1,3 +1,3 @@
 trait MyTrait {}
-impl !MyTrait for u32 {} //~ ERROR negative trait bounds are not yet fully implemented
+impl !MyTrait for u32 {} //~ ERROR negative trait bounds are not fully implemented
 fn main() {}
diff --git a/tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr b/tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr
index f3dee114116..1777dfcc993 100644
--- a/tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr
+++ b/tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr
@@ -1,4 +1,4 @@
-error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now
+error[E0658]: negative trait bounds are not fully implemented; use marker types for now
   --> $DIR/feature-gate-negative_impls.rs:2:6
    |
 LL | impl !MyTrait for u32 {}
diff --git a/tests/ui/unsafe-binders/expr.rs b/tests/ui/unsafe-binders/expr.rs
index d8c4c2df2cd..0fe68751f0a 100644
--- a/tests/ui/unsafe-binders/expr.rs
+++ b/tests/ui/unsafe-binders/expr.rs
@@ -4,10 +4,11 @@
 use std::unsafe_binder::{wrap_binder, unwrap_binder};
 
 fn main() {
+    unsafe {
     let x = 1;
-    let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
-    //~^ ERROR unsafe binders are not yet implemented
-    //~| ERROR unsafe binders are not yet implemented
-    let rx = *unwrap_binder!(binder);
-    //~^ ERROR unsafe binders are not yet implemented
+        let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
+        //~^ ERROR unsafe binder casts are not fully implemented
+        let rx = *unwrap_binder!(binder);
+        //~^ ERROR unsafe binder casts are not fully implemented
+    }
 }
diff --git a/tests/ui/unsafe-binders/expr.stderr b/tests/ui/unsafe-binders/expr.stderr
index 26fae1958b0..78a288e10a3 100644
--- a/tests/ui/unsafe-binders/expr.stderr
+++ b/tests/ui/unsafe-binders/expr.stderr
@@ -7,23 +7,17 @@ LL | #![feature(unsafe_binders)]
    = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: unsafe binders are not yet implemented
-  --> $DIR/expr.rs:8:17
+error: unsafe binder casts are not fully implemented
+  --> $DIR/expr.rs:9:55
    |
-LL |     let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
-   |                 ^^^^^^^^^^^^^^^^^^
+LL |         let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
+   |                                                       ^^
 
-error: unsafe binders are not yet implemented
-  --> $DIR/expr.rs:8:51
+error: unsafe binder casts are not fully implemented
+  --> $DIR/expr.rs:11:34
    |
-LL |     let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
-   |                                                   ^
+LL |         let rx = *unwrap_binder!(binder);
+   |                                  ^^^^^^
 
-error: unsafe binders are not yet implemented
-  --> $DIR/expr.rs:11:30
-   |
-LL |     let rx = *unwrap_binder!(binder);
-   |                              ^^^^^^
-
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/unsafe-binders/lifetime-resolution.rs b/tests/ui/unsafe-binders/lifetime-resolution.rs
index aebed9599d4..b352acfadf2 100644
--- a/tests/ui/unsafe-binders/lifetime-resolution.rs
+++ b/tests/ui/unsafe-binders/lifetime-resolution.rs
@@ -3,16 +3,13 @@
 
 fn foo<'a>() {
     let good: unsafe<'b> &'a &'b ();
-    //~^ ERROR unsafe binders are not yet implemented
 
     let missing: unsafe<> &'missing ();
-    //~^ ERROR unsafe binders are not yet implemented
-    //~| ERROR use of undeclared lifetime name `'missing`
+    //~^ ERROR use of undeclared lifetime name `'missing`
 
     fn inner<'b>() {
         let outer: unsafe<> &'a &'b ();
-        //~^ ERROR unsafe binders are not yet implemented
-        //~| can't use generic parameters from outer item
+        //~^ can't use generic parameters from outer item
     }
 }
 
diff --git a/tests/ui/unsafe-binders/lifetime-resolution.stderr b/tests/ui/unsafe-binders/lifetime-resolution.stderr
index 7a8ce929df1..69660c271bf 100644
--- a/tests/ui/unsafe-binders/lifetime-resolution.stderr
+++ b/tests/ui/unsafe-binders/lifetime-resolution.stderr
@@ -1,5 +1,5 @@
 error[E0261]: use of undeclared lifetime name `'missing`
-  --> $DIR/lifetime-resolution.rs:8:28
+  --> $DIR/lifetime-resolution.rs:7:28
    |
 LL |     let missing: unsafe<> &'missing ();
    |                            ^^^^^^^^ undeclared lifetime
@@ -15,7 +15,7 @@ LL | fn foo<'missing, 'a>() {
    |        +++++++++
 
 error[E0401]: can't use generic parameters from outer item
-  --> $DIR/lifetime-resolution.rs:13:30
+  --> $DIR/lifetime-resolution.rs:11:30
    |
 LL | fn foo<'a>() {
    |        -- lifetime parameter from outer item
@@ -41,25 +41,7 @@ LL | #![feature(unsafe_binders)]
    = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: unsafe binders are not yet implemented
-  --> $DIR/lifetime-resolution.rs:5:15
-   |
-LL |     let good: unsafe<'b> &'a &'b ();
-   |               ^^^^^^^^^^^^^^^^^^^^^
-
-error: unsafe binders are not yet implemented
-  --> $DIR/lifetime-resolution.rs:8:18
-   |
-LL |     let missing: unsafe<> &'missing ();
-   |                  ^^^^^^^^^^^^^^^^^^^^^
-
-error: unsafe binders are not yet implemented
-  --> $DIR/lifetime-resolution.rs:13:20
-   |
-LL |         let outer: unsafe<> &'a &'b ();
-   |                    ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0261, E0401.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/unsafe-binders/mismatch.rs b/tests/ui/unsafe-binders/mismatch.rs
new file mode 100644
index 00000000000..731fe2d1ce9
--- /dev/null
+++ b/tests/ui/unsafe-binders/mismatch.rs
@@ -0,0 +1,43 @@
+#![feature(unsafe_binders)]
+//~^ WARN the feature `unsafe_binders` is incomplete
+
+use std::unsafe_binder::{wrap_binder, unwrap_binder};
+
+fn a() {
+    let _: unsafe<'a> &'a i32 = wrap_binder!(&());
+    //~^ ERROR unsafe binder casts are not fully implemented
+    //~| ERROR mismatched types
+}
+
+fn b() {
+    let _: i32 = wrap_binder!(&());
+    //~^ ERROR unsafe binder casts are not fully implemented
+    //~| ERROR `wrap_binder!()` can only wrap into unsafe binder
+}
+
+fn c() {
+    let y = 1;
+    unwrap_binder!(y);
+    //~^ ERROR unsafe binder casts are not fully implemented
+    //~| ERROR expected unsafe binder, found integer as input
+}
+
+fn d() {
+    let unknown = Default::default();
+    unwrap_binder!(unknown);
+    //~^ ERROR unsafe binder casts are not fully implemented
+    // FIXME(unsafe_binders): This should report ambiguity once we've removed
+    // the error above which taints the infcx.
+}
+
+fn e() {
+    let x = wrap_binder!(&42);
+    //~^ ERROR unsafe binder casts are not fully implemented
+    // Currently, type inference doesn't flow backwards for unsafe binders.
+    // It could, perhaps, but that may cause even more surprising corners.
+    // FIXME(unsafe_binders): This should report ambiguity once we've removed
+    // the error above which taints the infcx.
+    let _: unsafe<'a> &'a i32 = x;
+}
+
+fn main() {}
diff --git a/tests/ui/unsafe-binders/mismatch.stderr b/tests/ui/unsafe-binders/mismatch.stderr
new file mode 100644
index 00000000000..a720e5dbdc1
--- /dev/null
+++ b/tests/ui/unsafe-binders/mismatch.stderr
@@ -0,0 +1,68 @@
+warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/mismatch.rs:1:12
+   |
+LL | #![feature(unsafe_binders)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: unsafe binder casts are not fully implemented
+  --> $DIR/mismatch.rs:7:46
+   |
+LL |     let _: unsafe<'a> &'a i32 = wrap_binder!(&());
+   |                                              ^^^
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch.rs:7:46
+   |
+LL |     let _: unsafe<'a> &'a i32 = wrap_binder!(&());
+   |                                              ^^^ expected `&i32`, found `&()`
+   |
+   = note: expected reference `&i32`
+              found reference `&()`
+
+error: unsafe binder casts are not fully implemented
+  --> $DIR/mismatch.rs:13:31
+   |
+LL |     let _: i32 = wrap_binder!(&());
+   |                               ^^^
+
+error: `wrap_binder!()` can only wrap into unsafe binder, not `i32`
+  --> $DIR/mismatch.rs:13:18
+   |
+LL |     let _: i32 = wrap_binder!(&());
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: unsafe binders are the only valid output of wrap
+   = note: this error originates in the macro `wrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unsafe binder casts are not fully implemented
+  --> $DIR/mismatch.rs:20:20
+   |
+LL |     unwrap_binder!(y);
+   |                    ^
+
+error: expected unsafe binder, found integer as input of `unwrap_binder!()`
+  --> $DIR/mismatch.rs:20:20
+   |
+LL |     unwrap_binder!(y);
+   |                    ^
+   |
+   = note: only an unsafe binder type can be unwrapped
+
+error: unsafe binder casts are not fully implemented
+  --> $DIR/mismatch.rs:27:20
+   |
+LL |     unwrap_binder!(unknown);
+   |                    ^^^^^^^
+
+error: unsafe binder casts are not fully implemented
+  --> $DIR/mismatch.rs:34:26
+   |
+LL |     let x = wrap_binder!(&42);
+   |                          ^^^
+
+error: aborting due to 8 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/unsafe-binders/simple.rs b/tests/ui/unsafe-binders/simple.rs
index cebff2cbfb8..6172a9e1e7b 100644
--- a/tests/ui/unsafe-binders/simple.rs
+++ b/tests/ui/unsafe-binders/simple.rs
@@ -1,7 +1,8 @@
+//@ check-pass
+
 #![feature(unsafe_binders)]
 //~^ WARN the feature `unsafe_binders` is incomplete
 
 fn main() {
     let x: unsafe<'a> &'a ();
-    //~^ ERROR unsafe binders are not yet implemented
 }
diff --git a/tests/ui/unsafe-binders/simple.stderr b/tests/ui/unsafe-binders/simple.stderr
index a21dbd00b4c..e4b82c12b06 100644
--- a/tests/ui/unsafe-binders/simple.stderr
+++ b/tests/ui/unsafe-binders/simple.stderr
@@ -1,5 +1,5 @@
 warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/simple.rs:1:12
+  --> $DIR/simple.rs:3:12
    |
 LL | #![feature(unsafe_binders)]
    |            ^^^^^^^^^^^^^^
@@ -7,11 +7,5 @@ LL | #![feature(unsafe_binders)]
    = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: unsafe binders are not yet implemented
-  --> $DIR/simple.rs:5:12
-   |
-LL |     let x: unsafe<'a> &'a ();
-   |            ^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error; 1 warning emitted
+warning: 1 warning emitted