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

@ -504,7 +504,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
| Rvalue::Cast(..)
| Rvalue::BinaryOp(..)
| Rvalue::Aggregate(..)
| Rvalue::ShallowInitBox(..) => {
| Rvalue::ShallowInitBox(..)
| Rvalue::WrapUnsafeBinder(..) => {
// No modification is possible through these r-values.
return ValueOrPlace::TOP;
}

View file

@ -575,6 +575,9 @@ impl WriteInfo {
self.add_operand(op);
}
}
Rvalue::WrapUnsafeBinder(op, _) => {
self.add_operand(op);
}
Rvalue::ThreadLocalRef(_)
| Rvalue::NullaryOp(_, _)
| Rvalue::Ref(_, _, _)

View file

@ -476,6 +476,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
ProjectionElem::UnwrapUnsafeBinder(ty) => {
ProjectionElem::UnwrapUnsafeBinder(ty)
}
// This should have been replaced by a `ConstantIndex` earlier.
ProjectionElem::Index(_) => return None,
};
@ -713,6 +716,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
};
Some(self.insert(Value::Projection(value, proj)))
@ -867,6 +871,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
self.simplify_place_projection(place, location);
return self.new_pointer(*place, AddressKind::Address(mutbl));
}
Rvalue::WrapUnsafeBinder(ref mut op, _) => {
return self.simplify_operand(op, location);
}
// Operations.
Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
@ -931,6 +938,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx),
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
})
}

View file

@ -444,7 +444,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
| Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::Discriminant(..)
| Rvalue::NullaryOp(..) => {}
| Rvalue::NullaryOp(..)
| Rvalue::WrapUnsafeBinder(..) => {}
}
// FIXME we need to revisit this for #67176
@ -546,7 +547,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let val: Value<'_> = match *rvalue {
ThreadLocalRef(_) => return None,
Use(ref operand) => self.eval_operand(operand)?.into(),
Use(ref operand) | WrapUnsafeBinder(ref operand, _) => {
self.eval_operand(operand)?.into()
}
CopyForDeref(place) => self.eval_place(place)?.into(),

View file

@ -293,7 +293,8 @@ impl<'tcx> Validator<'_, 'tcx> {
// Recurse directly.
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subtype(_)
| ProjectionElem::Subslice { .. } => {}
| ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
// Never recurse.
ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
@ -426,7 +427,9 @@ impl<'tcx> Validator<'_, 'tcx> {
fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
match rvalue {
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
Rvalue::Use(operand)
| Rvalue::Repeat(operand, _)
| Rvalue::WrapUnsafeBinder(operand, _) => {
self.validate_operand(operand)?;
}
Rvalue::CopyForDeref(place) => {

View file

@ -807,6 +807,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
)
}
}
ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => {
let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx);
let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else {
self.fail(
location,
format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"),
);
return;
};
let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) {
self.fail(
location,
format!(
"Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty:?}"
),
);
}
}
_ => {}
}
self.super_projection_elem(place_ref, elem, context, location);
@ -1362,6 +1381,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
| Rvalue::RawPtr(_, _)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
| Rvalue::Discriminant(_) => {}
Rvalue::WrapUnsafeBinder(op, ty) => {
let unwrapped_ty = op.ty(self.body, self.tcx);
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
self.fail(
location,
format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"),
);
return;
};
let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) {
self.fail(
location,
format!("Cannot wrap {unwrapped_ty:?} into unsafe binder {binder_ty:?}"),
);
}
}
}
self.super_rvalue(rvalue, location);
}