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:
commit
2fd3007cbc
56 changed files with 589 additions and 102 deletions
|
@ -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})")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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! {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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: _,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue