From c37b9bd9b28eb147fc1fc0aabf5e551fcdb5d4e6 Mon Sep 17 00:00:00 2001 From: Sebastien Tardif Date: Tue, 23 Jun 2026 22:03:18 -0700 Subject: [PATCH] ty: handle UnsafeBinder in pointer_kind, metadata, and projections Avoid todo!() ICEs on unstable unsafe binders by following the inner type after erasing binder regions (same pattern as discriminant_ty / variant_range elsewhere). - hir_typeck::pointer_kind: recurse into inner type - ptr_metadata_ty_or_tail: delegate to inner - is_trivially_not_async_drop: conservative false without TyCtxt - project DiscriminantKind/Pointee: treat as inner type Closes #525 Signed-off-by: Sebastien Tardif --- compiler/rustc_hir_typeck/src/cast.rs | 7 +- compiler/rustc_middle/src/ty/sty.rs | 7 +- compiler/rustc_middle/src/ty/util.rs | 4 +- .../src/traits/project.rs | 77 ++++++++++++++++++- 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index c8680be6de718..37af51dad6509 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -118,7 +118,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(&f) => self.pointer_kind(f, span)?, }, - ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), + // Pointer kind follows the inner type once binder regions are erased, + // matching `discriminant_ty` / other ty queries on unsafe binders. + ty::UnsafeBinder(bound_ty) => { + let inner = self.tcx.instantiate_bound_regions_with_erased((*bound_ty).into()); + self.pointer_kind(inner, span)? + } // Pointers to foreign types are thin, despite being unsized ty::Foreign(..) => Some(PointerKind::Thin), diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 93f0afda372f7..f83eaccf4f597 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1790,7 +1790,12 @@ impl<'tcx> Ty<'tcx> { // metadata of `tail`. ty::Param(_) | ty::Alias(..) => Err(tail), - ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), + // Metadata of an unsafe binder is the metadata of its inner type + // (regions erased), same as other queries on `UnsafeBinder`. + ty::UnsafeBinder(bound_ty) => { + tcx.instantiate_bound_regions_with_erased((*bound_ty).into()) + .ptr_metadata_ty_or_tail(tcx, normalize) + } ty::Infer(ty::TyVar(_)) | ty::Pat(..) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ee6aaf9cb6e17..ae177735ff636 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1268,8 +1268,8 @@ impl<'tcx> Ty<'tcx> { | ty::FnDef(..) | ty::Error(_) | ty::FnPtr(..) => true, - // FIXME(unsafe_binders): - ty::UnsafeBinder(_) => todo!(), + // Without `TyCtxt` we cannot erase binder regions; be conservative. + ty::UnsafeBinder(_) => false, ty::Tuple(fields) => fields.iter().all(Self::is_trivially_not_async_drop), ty::Pat(elem_ty, _) | ty::Slice(elem_ty) | ty::Array(elem_ty, _) => { elem_ty.is_trivially_not_async_drop() diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index e267d18515a40..8615a1da0243d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1084,7 +1084,40 @@ 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)"), + // DiscriminantKind on unsafe binders follows the inner type (see `discriminant_ty`). + ty::UnsafeBinder(bound_ty) => { + let inner = selcx + .tcx() + .instantiate_bound_regions_with_erased((*bound_ty).into()); + match inner.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Foreign(_) + | ty::Str + | ty::Array(..) + | ty::Pat(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(..) + | ty::Infer( + ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..), + ) => true, + _ => false, + } + } // type parameters, opaques, and unnormalized projections don't have // a known discriminant and may need to be normalized further or rely @@ -1169,7 +1202,47 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( true } - ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), + // Pointee/metadata of an unsafe binder is that of the inner type. + ty::UnsafeBinder(bound_ty) => { + let inner = selcx + .tcx() + .instantiate_bound_regions_with_erased((*bound_ty).into()); + match *inner.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(..) + | ty::Pat(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Foreign(_) + | ty::Adt(..) + | ty::Tuple(..) + | ty::Infer( + ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..), + ) + | ty::Error(..) => true, + ty::Param(_) | ty::Alias(..) if self_ty != tail => true, + _ => { + if tail.has_infer_types() { + candidate_set.mark_ambiguous(); + } + false + } + } + } // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? ty::Param(_)