1
Fork 0

Rollup merge of #130514 - compiler-errors:unsafe-binders, r=oli-obk

Implement MIR lowering for unsafe binders

This is the final bit of the unsafe binders puzzle. It implements MIR, CTFE, and codegen for unsafe binders, and enforces that (for now) they are `Copy`. Later on, I'll introduce a new trait that relaxes this requirement to being "is `Copy` or `ManuallyDrop<T>`" which more closely models how we treat union fields.

Namely, wrapping unsafe binders is now `Rvalue::WrapUnsafeBinder`, which acts much like an `Rvalue::Aggregate`. Unwrapping unsafe binders are implemented as a MIR projection `ProjectionElem::UnwrapUnsafeBinder`, which acts much like `ProjectionElem::Field`.

Tracking:
- https://github.com/rust-lang/rust/issues/130516
This commit is contained in:
Matthias Krüger 2025-02-01 16:41:03 +01:00 committed by GitHub
commit 2fd3007cbc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 589 additions and 102 deletions

View file

@ -1248,6 +1248,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
ShallowInitBox(ref place, ref ty) => {
with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
}
WrapUnsafeBinder(ref op, ty) => {
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
}
}
}
}
@ -1308,6 +1312,9 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {}
ProjectionElem::UnwrapUnsafeBinder(_) => {
write!(fmt, "unwrap_binder!(")?;
}
}
}
@ -1356,6 +1363,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
ProjectionElem::Subslice { from, to, from_end: false } => {
write!(fmt, "[{from:?}..{to:?}]")?;
}
ProjectionElem::UnwrapUnsafeBinder(ty) => {
write!(fmt, "; {ty})")?;
}
}
}

View file

@ -62,7 +62,8 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Subtype(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => false,
| Self::Downcast(_, _)
| Self::UnwrapUnsafeBinder(..) => false,
}
}
@ -76,7 +77,8 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Subtype(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => true,
| Self::Downcast(_, _)
| Self::UnwrapUnsafeBinder(..) => true,
}
}
@ -102,6 +104,9 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Subtype(_)
| Self::OpaqueCast(_)
| Self::Subslice { .. } => false,
// FIXME(unsafe_binders): Figure this out.
Self::UnwrapUnsafeBinder(..) => false,
}
}
}
@ -443,7 +448,8 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::UnaryOp(_, _)
| Rvalue::Discriminant(_)
| Rvalue::Aggregate(_, _)
| Rvalue::ShallowInitBox(_, _) => true,
| Rvalue::ShallowInitBox(_, _)
| Rvalue::WrapUnsafeBinder(_, _) => true,
}
}
}

View file

@ -1276,6 +1276,10 @@ pub enum ProjectionElem<V, T> {
/// requiring an intermediate variable.
OpaqueCast(T),
/// A transmute from an unsafe binder to the type that it wraps. This is a projection
/// of a place, so it doesn't necessarily constitute a move out of the binder.
UnwrapUnsafeBinder(T),
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
/// explicit during optimizations and codegen.
@ -1493,6 +1497,9 @@ pub enum Rvalue<'tcx> {
/// optimizations and codegen backends that previously had to handle deref operations anywhere
/// in a place.
CopyForDeref(Place<'tcx>),
/// Wraps a value in an unsafe binder.
WrapUnsafeBinder(Operand<'tcx>, Ty<'tcx>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]

View file

@ -146,6 +146,11 @@ impl<'tcx> PlaceTy<'tcx> {
ProjectionElem::Subtype(ty) => {
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
}
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
ProjectionElem::UnwrapUnsafeBinder(ty) => {
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
}
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer
@ -241,6 +246,7 @@ impl<'tcx> Rvalue<'tcx> {
},
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
Rvalue::WrapUnsafeBinder(_, ty) => ty,
}
}

View file

@ -1,6 +1,7 @@
//! `TypeFoldable` implementations for MIR types
use rustc_ast::InlineAsmTemplatePiece;
use rustc_hir::UnsafeBinderCastKind;
use rustc_hir::def_id::LocalDefId;
use super::*;
@ -21,6 +22,7 @@ TrivialTypeTraversalImpls! {
SwitchTargets,
CoroutineKind,
CoroutineSavedLocal,
UnsafeBinderCastKind,
}
TrivialTypeTraversalImpls! {

View file

@ -781,6 +781,11 @@ macro_rules! make_mir_visitor {
self.visit_operand(operand, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
Rvalue::WrapUnsafeBinder(op, ty) => {
self.visit_operand(op, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
}
}
@ -1151,6 +1156,11 @@ macro_rules! visit_place_fns {
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
}
PlaceElem::UnwrapUnsafeBinder(ty) => {
let mut new_ty = ty;
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None }
}
PlaceElem::Deref
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
@ -1219,7 +1229,8 @@ macro_rules! visit_place_fns {
match elem {
ProjectionElem::OpaqueCast(ty)
| ProjectionElem::Subtype(ty)
| ProjectionElem::Field(_, ty) => {
| ProjectionElem::Field(_, ty)
| ProjectionElem::UnwrapUnsafeBinder(ty) => {
self.visit_ty(ty, TyContext::Location(location));
}
ProjectionElem::Index(local) => {

View file

@ -489,6 +489,19 @@ pub enum ExprKind<'tcx> {
user_ty: UserTy<'tcx>,
user_ty_span: Span,
},
/// An unsafe binder cast on a place, e.g. `unwrap_binder!(*ptr)`.
PlaceUnwrapUnsafeBinder {
source: ExprId,
},
/// An unsafe binder cast on a value, e.g. `unwrap_binder!(rvalue())`,
/// which makes a temporary.
ValueUnwrapUnsafeBinder {
source: ExprId,
},
/// Construct an unsafe binder, e.g. `wrap_binder(&ref)`.
WrapUnsafeBinder {
source: ExprId,
},
/// A closure definition.
Closure(Box<ClosureExpr<'tcx>>),
/// A literal.

View file

@ -136,6 +136,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
| ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
visitor.visit_expr(&visitor.thir()[source])
}
PlaceUnwrapUnsafeBinder { source }
| ValueUnwrapUnsafeBinder { source }
| WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]),
Closure(box ClosureExpr {
closure_id: _,
args: _,