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

@ -1657,7 +1657,7 @@ impl GenBlockKind {
}
/// Whether we're unwrapping or wrapping an unsafe binder
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum UnsafeBinderCastKind {
// e.g. `&i32` -> `unsafe<'a> &'a i32`

View file

@ -3915,7 +3915,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(_)
| ProjectionElem::Index(_) => kind,
| ProjectionElem::Index(_)
| ProjectionElem::UnwrapUnsafeBinder(_) => kind,
},
place_ty.projection_ty(tcx, elem),
)

View file

@ -370,6 +370,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
ProjectionElem::Downcast(..) => (),
ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Subtype(..) => (),
ProjectionElem::UnwrapUnsafeBinder(_) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@ -450,9 +451,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
PlaceTy::from_ty(*ty)
}
ProjectionElem::Subtype(ty)
| ProjectionElem::OpaqueCast(ty)
| ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};

View file

@ -167,7 +167,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
| ProjectionElem::Downcast(..)
| ProjectionElem::UnwrapUnsafeBinder(_),
],
} => bug!("Unexpected immutable place."),
}

View file

@ -1398,6 +1398,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
self.consume_operand(location, (operand, span), state);
}
}
Rvalue::WrapUnsafeBinder(op, _) => {
self.consume_operand(location, (op, span), state);
}
}
}
@ -1770,7 +1774,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// So it's safe to skip these.
ProjectionElem::OpaqueCast(_)
| ProjectionElem::Subtype(_)
| ProjectionElem::Downcast(_, _) => (),
| ProjectionElem::Downcast(_, _)
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
}
place_ty = place_ty.projection_ty(tcx, elem);
@ -2004,6 +2009,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// FIXME: is this true even if P is an adt with a dtor?
{ }
ProjectionElem::UnwrapUnsafeBinder(_) => {
check_parent_of_field(self, location, place_base, span, state);
}
// assigning to (*P) requires P to be initialized
ProjectionElem::Deref => {
self.check_if_full_path_is_moved(
@ -2384,7 +2393,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(..)
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => {
| ProjectionElem::Downcast(..)
| ProjectionElem::UnwrapUnsafeBinder(_) => {
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let upvar = &self.upvars[field.index()];

View file

@ -250,7 +250,8 @@ fn place_components_conflict<'tcx>(
| (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Subtype(_), _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
| (ProjectionElem::Downcast { .. }, _, _)
| (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
// there's a deref later on, e.g., a borrow
@ -519,5 +520,9 @@ fn place_projection_conflict<'tcx>(
pi1_elem,
pi2_elem
),
(ProjectionElem::UnwrapUnsafeBinder(_), _) => {
todo!()
}
}
}

View file

@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
self.consume_operand(location, operand);
}
}
Rvalue::WrapUnsafeBinder(op, _) => {
self.consume_operand(location, op);
}
}
}

View file

@ -66,6 +66,10 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
self.next = Some(cursor_base);
return Some(cursor);
}
ProjectionElem::UnwrapUnsafeBinder(_) => {
self.next = Some(cursor_base);
return Some(cursor);
}
ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::OpaqueCast { .. }

View file

@ -302,6 +302,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
)
.unwrap();
}
ProjectionElem::UnwrapUnsafeBinder(ty) => {
let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else {
unreachable!();
};
let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars(
self.body().source_info(location).span,
BoundRegionConversionTime::HigherRankedType,
binder_ty.into(),
);
self.typeck
.relate_types(
ty,
context.ambient_variance(),
found_ty,
location.to_locations(),
ConstraintCategory::Boring,
)
.unwrap();
}
ProjectionElem::Subtype(_) => {
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
}
@ -2233,6 +2252,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_operand(right, location);
}
Rvalue::WrapUnsafeBinder(op, ty) => {
self.check_operand(op, location);
let operand_ty = op.ty(self.body, self.tcx());
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
unreachable!();
};
let expected_ty = self.infcx.instantiate_binder_with_fresh_vars(
self.body().source_info(location).span,
BoundRegionConversionTime::HigherRankedType,
binder_ty.into(),
);
self.sub_types(
operand_ty,
expected_ty,
location.to_locations(),
ConstraintCategory::Boring,
)
.unwrap();
}
Rvalue::RawPtr(..)
| Rvalue::ThreadLocalRef(..)
| Rvalue::Len(..)
@ -2258,7 +2298,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| Rvalue::NullaryOp(..)
| Rvalue::CopyForDeref(..)
| Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => None,
| Rvalue::Discriminant(..)
| Rvalue::WrapUnsafeBinder(..) => None,
Rvalue::Aggregate(aggregate, _) => match **aggregate {
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
@ -2450,7 +2491,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
| ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {
// other field access
}
ProjectionElem::Subtype(_) => {

View file

@ -925,6 +925,10 @@ fn codegen_stmt<'tcx>(
}
crate::discriminant::codegen_set_discriminant(fx, lval, variant_index);
}
Rvalue::WrapUnsafeBinder(ref operand, _to_ty) => {
let operand = codegen_operand(fx, operand);
lval.write_cvalue_transmute(fx, operand);
}
}
}
StatementKind::StorageLive(_)
@ -993,7 +997,9 @@ pub(crate) fn codegen_place<'tcx>(
cplace = cplace.place_deref(fx);
}
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)),
PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => {
cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
}
PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field);
}

View file

@ -502,6 +502,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bug!("encountered OpaqueCast({ty}) in codegen")
}
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
cg_base.project_type(bx, self.monomorphize(ty))
}
mir::ProjectionElem::Index(index) => {
let index = &mir::Operand::Copy(mir::Place::from(index));
let index = self.codegen_operand(bx, index);

View file

@ -823,6 +823,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandRef { val: OperandValue::Immediate(val), layout: box_layout }
}
mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => {
let operand = self.codegen_operand(bx, operand);
let binder_ty = self.monomorphize(binder_ty);
let layout = bx.cx().layout_of(binder_ty);
OperandRef { val: operand.val, layout }
}
}
}
@ -1123,7 +1129,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::Rvalue::Discriminant(..) |
mir::Rvalue::NullaryOp(..) |
mir::Rvalue::ThreadLocalRef(_) |
mir::Rvalue::Use(..) => // (*)
mir::Rvalue::Use(..) |
mir::Rvalue::WrapUnsafeBinder(..) => // (*)
true,
// Arrays are always aggregates, so it's not worth checking anything here.
// (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)

View file

@ -728,6 +728,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
);
}
}
Rvalue::WrapUnsafeBinder(..) => {
// Unsafe binders are always trivial to create.
}
}
}

View file

@ -258,6 +258,8 @@ where
in_place::<Q, _>(cx, in_local, place.as_ref())
}
Rvalue::WrapUnsafeBinder(op, _) => in_operand::<Q, _>(cx, in_local, op),
Rvalue::Aggregate(kind, operands) => {
// Return early if we know that the struct or enum being constructed is always
// qualified.
@ -297,7 +299,8 @@ where
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(_, _)
| ProjectionElem::Index(_) => {}
| ProjectionElem::Index(_)
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
}
let base_ty = place_base.ty(cx.body, cx.tcx);

View file

@ -202,7 +202,8 @@ where
| mir::Rvalue::NullaryOp(..)
| mir::Rvalue::UnaryOp(..)
| mir::Rvalue::Discriminant(..)
| mir::Rvalue::Aggregate(..) => {}
| mir::Rvalue::Aggregate(..)
| mir::Rvalue::WrapUnsafeBinder(..) => {}
}
}

View file

@ -381,6 +381,7 @@ where
OpaqueCast(ty) => {
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
}
UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
// We don't want anything happening here, this is here as a dummy.
Subtype(_) => base.transmute(base.layout(), self)?,
Field(field, _) => self.project_field(base, field.index())?,

View file

@ -277,6 +277,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
self.write_immediate(*discr, &dest)?;
}
WrapUnsafeBinder(ref op, _ty) => {
// Constructing an unsafe binder acts like a transmute
// since the operand's layout does not change.
let op = self.eval_operand(op, None)?;
self.copy_op_allow_transmute(&op, &dest)?;
}
}
trace!("{:?}", self.dump_place(&dest));

View file

@ -1658,8 +1658,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
match kind {
hir::UnsafeBinderCastKind::Wrap => {
let ascribed_ty =

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: _,

View file

@ -361,6 +361,18 @@ mir_build_unreachable_pattern = unreachable pattern
.unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings
.suggestion = remove the match arm
mir_build_unsafe_binder_cast_requires_unsafe =
unsafe binder cast is unsafe and requires unsafe block
.label = unsafe binder cast
.note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
information that may be required to uphold safety guarantees of a type
mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
unsafe binder cast is unsafe and requires unsafe block or unsafe fn
.label = unsafe binder cast
.note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
information that may be required to uphold safety guarantees of a type
mir_build_unsafe_field_requires_unsafe =
use of unsafe field is unsafe and requires unsafe block
.note = unsafe fields may carry library invariants

View file

@ -105,7 +105,8 @@ fn convert_to_hir_projections_and_truncate_for_capture(
ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
| ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {
// We don't capture array-access projections.
// We can stop here as arrays are captured completely.
break;
@ -523,6 +524,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(PlaceBuilder::from(temp))
}
ExprKind::PlaceUnwrapUnsafeBinder { source } => {
let place_builder = unpack!(
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
);
block.and(place_builder.project(PlaceElem::UnwrapUnsafeBinder(expr.ty)))
}
ExprKind::ValueUnwrapUnsafeBinder { source } => {
let source_expr = &this.thir[source];
let temp = unpack!(
block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
);
block.and(PlaceBuilder::from(temp).project(PlaceElem::UnwrapUnsafeBinder(expr.ty)))
}
ExprKind::Array { .. }
| ExprKind::Tuple { .. }
| ExprKind::Adt { .. }
@ -560,7 +575,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::OffsetOf { .. }
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. } => {
| ExprKind::Call { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
// these are not places, so we need to make a temporary.
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
let temp =
@ -776,7 +792,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subtype(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => (),
| ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
}
}
}

View file

@ -508,6 +508,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(Rvalue::Use(Operand::Constant(Box::new(constant))))
}
ExprKind::WrapUnsafeBinder { source } => {
let source = unpack!(
block = this.as_operand(
block,
scope,
source,
LocalInfo::Boring,
NeedsTemporary::Maybe
)
);
block.and(Rvalue::WrapUnsafeBinder(source, expr.ty))
}
ExprKind::Yield { .. }
| ExprKind::Block { .. }
| ExprKind::Match { .. }
@ -532,7 +545,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Become { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => {
| ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. } => {
// these do not have corresponding `Rvalue` variants,
// so make an operand and then return that
debug_assert!(!matches!(

View file

@ -41,7 +41,9 @@ impl Category {
| ExprKind::UpvarRef { .. }
| ExprKind::VarRef { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
| ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. } => Some(Category::Place),
ExprKind::LogicalOp { .. }
| ExprKind::Match { .. }
@ -68,7 +70,8 @@ impl Category {
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
| ExprKind::OffsetOf { .. }
| ExprKind::WrapUnsafeBinder { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
ExprKind::ConstBlock { .. }
| ExprKind::Literal { .. }

View file

@ -554,7 +554,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::VarRef { .. }
| ExprKind::UpvarRef { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => {
| ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. } => {
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
let place = unpack!(block = this.as_place(block, expr_id));
@ -613,7 +615,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ConstParam { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::StaticRef { .. }
| ExprKind::OffsetOf { .. } => {
| ExprKind::OffsetOf { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
debug_assert!(match Category::of(&expr.kind).unwrap() {
// should be handled above
Category::Rvalue(RvalueFunc::Into) => false,

View file

@ -439,6 +439,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::NeverToAny { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. }
| ExprKind::WrapUnsafeBinder { .. }
| ExprKind::PointerCoercion { .. }
| ExprKind::Repeat { .. }
| ExprKind::StaticRef { .. }
@ -680,6 +683,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
}
}
ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
self.requires_unsafe(expr.span, UnsafeBinderCast);
}
_ => {}
}
visit::walk_expr(self, expr);
@ -728,6 +736,7 @@ enum UnsafeOpKind {
/// (e.g., with `-C target-feature`).
build_enabled: Vec<Symbol>,
},
UnsafeBinderCast,
}
use UnsafeOpKind::*;
@ -891,6 +900,15 @@ impl UnsafeOpKind {
unsafe_not_inherited_note,
},
),
UnsafeBinderCast => tcx.emit_node_span_lint(
UNSAFE_OP_IN_UNSAFE_FN,
hir_id,
span,
UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
span,
unsafe_not_inherited_note,
},
),
}
}
@ -1099,6 +1117,15 @@ impl UnsafeOpKind {
function: tcx.def_path_str(*function),
});
}
UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => {
dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
span,
unsafe_not_inherited_note,
});
}
UnsafeBinderCast => {
dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
}
}
}
}

View file

@ -160,6 +160,18 @@ pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
}
#[derive(LintDiagnostic)]
#[diag(
mir_build_unsafe_binder_cast_requires_unsafe,
code = E0133,
)]
pub(crate) struct UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
#[label]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)]
#[help]
@ -494,6 +506,32 @@ pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}
#[derive(Diagnostic)]
#[diag(
mir_build_unsafe_binder_cast_requires_unsafe,
code = E0133,
)]
pub(crate) struct UnsafeBinderCastRequiresUnsafe {
#[primary_span]
#[label]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}
#[derive(Diagnostic)]
#[diag(
mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
code = E0133,
)]
pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
#[primary_span]
#[label]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}
#[derive(Subdiagnostic)]
#[label(mir_build_unsafe_not_inherited)]
pub(crate) struct UnsafeNotInheritedNote {

View file

@ -1,5 +1,6 @@
use itertools::Itertools;
use rustc_abi::{FIRST_VARIANT, FieldIdx};
use rustc_ast::UnsafeBinderCastKind;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@ -910,8 +911,19 @@ impl<'tcx> Cx<'tcx> {
}
}
hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
unreachable!("unsafe binders are not yet implemented")
hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, source, _ty) => {
// FIXME(unsafe_binders): Take into account the ascribed type, too.
let mirrored = self.mirror_expr(source);
if source.is_syntactic_place_expr() {
ExprKind::PlaceUnwrapUnsafeBinder { source: mirrored }
} else {
ExprKind::ValueUnwrapUnsafeBinder { source: mirrored }
}
}
hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, source, _ty) => {
// FIXME(unsafe_binders): Take into account the ascribed type, too.
let mirrored = self.mirror_expr(source);
ExprKind::WrapUnsafeBinder { source: mirrored }
}
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },

View file

@ -326,9 +326,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
| Use { source }
| PointerCoercion { source, .. }
| PlaceTypeAscription { source, .. }
| ValueTypeAscription { source, .. } => {
self.is_known_valid_scrutinee(&self.thir()[*source])
}
| ValueTypeAscription { source, .. }
| PlaceUnwrapUnsafeBinder { source }
| ValueUnwrapUnsafeBinder { source }
| WrapUnsafeBinder { source } => self.is_known_valid_scrutinee(&self.thir()[*source]),
// These diverge.
Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true,

View file

@ -477,6 +477,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
PlaceUnwrapUnsafeBinder { source } => {
print_indented!(self, "PlaceUnwrapUnsafeBinder {", depth_lvl);
print_indented!(self, "source:", depth_lvl + 1);
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
ValueUnwrapUnsafeBinder { source } => {
print_indented!(self, "ValueUnwrapUnsafeBinder {", depth_lvl);
print_indented!(self, "source:", depth_lvl + 1);
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
WrapUnsafeBinder { source } => {
print_indented!(self, "WrapUnsafeBinder {", depth_lvl);
print_indented!(self, "source:", depth_lvl + 1);
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
Closure(closure_expr) => {
print_indented!(self, "Closure {", depth_lvl);
print_indented!(self, "closure_expr:", depth_lvl + 1);

View file

@ -97,7 +97,8 @@ where
| Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..)
| Rvalue::Aggregate(..)
| Rvalue::CopyForDeref(..) => {}
| Rvalue::CopyForDeref(..)
| Rvalue::WrapUnsafeBinder(..) => {}
}
}

View file

@ -32,6 +32,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
}
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()),
ProjectionElem::UnwrapUnsafeBinder(_ty) => ProjectionElem::UnwrapUnsafeBinder(()),
}
}
}

View file

@ -208,7 +208,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| ty::Infer(_)
| ty::Error(_)
| ty::Placeholder(_) => bug!(
"When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
"When Place contains ProjectionElem::Field its type shouldn't be {place_ty:#?}"
),
},
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
@ -226,6 +226,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
}
_ => bug!("Unexpected type {place_ty:#?}"),
},
ProjectionElem::UnwrapUnsafeBinder(_) => {}
// `OpaqueCast`:Only transmutes the type, so no moves there.
// `Downcast` :Only changes information about a `Place` without moving.
// `Subtype` :Only transmutes the type, so moves.
@ -399,7 +400,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| Rvalue::Repeat(ref operand, _)
| Rvalue::Cast(_, ref operand, _)
| Rvalue::ShallowInitBox(ref operand, _)
| Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
| Rvalue::UnaryOp(_, ref operand)
| Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
self.gather_operand(lhs);
self.gather_operand(rhs);

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);
}

View file

@ -217,6 +217,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
}
CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
}
}
}
@ -395,6 +396,7 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
}
}
}

View file

@ -2152,7 +2152,6 @@ symbols! {
unwrap,
unwrap_binder,
unwrap_or,
unwrap_unsafe_binder,
use_extern_macros,
use_nested_groups,
used,

View file

@ -830,8 +830,25 @@ 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::UnsafeBinder(ty) => {
// FIXME(unsafe_binders): For now, we have no way to express
// that a type must be `ManuallyDrop` OR `Copy` (or a pointer).
if !ty.has_escaping_bound_vars() {
self.out.push(traits::Obligation::new(
self.tcx(),
self.cause(ObligationCauseCode::Misc),
self.param_env,
ty.map_bound(|ty| {
ty::TraitRef::new(
self.tcx(),
self.tcx().require_lang_item(LangItem::Copy, Some(self.span)),
[ty],
)
}),
));
}
// We recurse into the binder below.
}
ty::Dynamic(data, r, _) => {

View file

@ -116,6 +116,11 @@ fn recurse_build<'tcx>(
| &ExprKind::ValueTypeAscription { source, .. } => {
recurse_build(tcx, body, source, root_span)?
}
&ExprKind::PlaceUnwrapUnsafeBinder { .. }
| &ExprKind::ValueUnwrapUnsafeBinder { .. }
| &ExprKind::WrapUnsafeBinder { .. } => {
todo!("FIXME(unsafe_binders)")
}
&ExprKind::Literal { lit, neg } => {
let sp = node.span;
tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg })
@ -347,6 +352,9 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
| thir::ExprKind::Adt(_)
| thir::ExprKind::PlaceTypeAscription { .. }
| thir::ExprKind::ValueTypeAscription { .. }
| thir::ExprKind::PlaceUnwrapUnsafeBinder { .. }
| thir::ExprKind::ValueUnwrapUnsafeBinder { .. }
| thir::ExprKind::WrapUnsafeBinder { .. }
| thir::ExprKind::Closure(_)
| thir::ExprKind::Literal { .. }
| thir::ExprKind::NonHirLiteral { .. }

View file

@ -116,6 +116,7 @@ fn check_rvalue<'tcx>(
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
Rvalue::Repeat(operand, _)
| Rvalue::Use(operand)
| Rvalue::WrapUnsafeBinder(operand, _)
| Rvalue::Cast(
CastKind::PointerWithExposedProvenance
| CastKind::IntToInt
@ -289,7 +290,8 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
| ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(_)
| ProjectionElem::Index(_) => {},
| ProjectionElem::Index(_)
| ProjectionElem::UnwrapUnsafeBinder(_) => {},
}
}

View file

@ -1,3 +1,5 @@
//@ check-pass
#![feature(unsafe_binders)]
//~^ WARN the feature `unsafe_binders` is incomplete
@ -7,8 +9,6 @@ fn main() {
unsafe {
let x = 1;
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
}
}

View file

@ -1,5 +1,5 @@
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/expr.rs:1:12
--> $DIR/expr.rs:3:12
|
LL | #![feature(unsafe_binders)]
| ^^^^^^^^^^^^^^
@ -7,17 +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 binder casts are not fully implemented
--> $DIR/expr.rs:9:55
|
LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
| ^^
error: unsafe binder casts are not fully implemented
--> $DIR/expr.rs:11:34
|
LL | let rx = *unwrap_binder!(binder);
| ^^^^^^
error: aborting due to 2 previous errors; 1 warning emitted
warning: 1 warning emitted

View file

@ -5,38 +5,31 @@ 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
//~^ 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
//~^ 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
//~^ ERROR expected unsafe binder, found integer as input
}
fn d() {
let unknown = Default::default();
//~^ ERROR type annotations needed
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
//~^ ERROR type annotations needed
// 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;
}

View file

@ -7,12 +7,6 @@ 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
|
@ -22,14 +16,8 @@ LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&());
= 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
--> $DIR/mismatch.rs:12:18
|
LL | let _: i32 = wrap_binder!(&());
| ^^^^^^^^^^^^^^^^^
@ -37,32 +25,35 @@ 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
--> $DIR/mismatch.rs:18: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
error[E0282]: type annotations needed
--> $DIR/mismatch.rs:23:9
|
LL | unwrap_binder!(unknown);
LL | let unknown = Default::default();
| ^^^^^^^
LL |
LL | unwrap_binder!(unknown);
| ------- type must be known at this point
|
help: consider giving `unknown` an explicit type
|
LL | let unknown: /* Type */ = Default::default();
| ++++++++++++
error: unsafe binder casts are not fully implemented
--> $DIR/mismatch.rs:34:26
error[E0282]: type annotations needed
--> $DIR/mismatch.rs:29:26
|
LL | let x = wrap_binder!(&42);
| ^^^
| ^^^ cannot infer type
error: aborting due to 8 previous errors; 1 warning emitted
error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0308`.
Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.

View file

@ -0,0 +1,41 @@
//@ known-bug: unknown
#![feature(unsafe_binders)]
// FIXME(unsafe_binders) ~^ WARN the feature `unsafe_binders` is incomplete
use std::unsafe_binder::{wrap_binder, unwrap_binder};
use std::mem::{drop, ManuallyDrop};
struct NotCopyInner;
type NotCopy = ManuallyDrop<NotCopyInner>;
fn use_after_wrap() {
unsafe {
let base = NotCopy;
let binder: unsafe<> NotCopy = wrap_binder!(base);
drop(base);
// FIXME(unsafe_binders) ~^ ERROR use of moved value: `base`
}
}
fn move_out_of_wrap() {
unsafe {
let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
drop(unwrap_binder!(binder));
drop(unwrap_binder!(binder));
// FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder`
}
}
fn not_conflicting() {
unsafe {
let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
drop(unwrap_binder!(binder).0);
drop(unwrap_binder!(binder).1);
// ^ NOT a problem.
drop(unwrap_binder!(binder).0);
// FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder.0`
}
}
fn main() {}

View file

@ -0,0 +1,85 @@
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:14:20
|
LL | let base = NotCopy;
| ^^^^^^^
|
= note: can't use a type alias as a constructor
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:23:53
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
| ^^^^^^^
|
= note: can't use a type alias as a constructor
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:32:65
|
LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
| ^^^^^^^
|
= note: can't use a type alias as a constructor
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:32:74
|
LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
| ^^^^^^^
|
= note: can't use a type alias as a constructor
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/moves.rs:3: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[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
--> $DIR/moves.rs:15:21
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(base);
| ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
|
= note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct NotCopyInner;
|
error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
--> $DIR/moves.rs:23:21
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
| ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
|
= note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct NotCopyInner;
|
error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
--> $DIR/moves.rs:32:21
|
LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
|
= note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
= note: required because it appears within the type `(ManuallyDrop<NotCopyInner>, ManuallyDrop<NotCopyInner>)`
help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct NotCopyInner;
|
error: aborting due to 7 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0423.
For more information about an error, try `rustc --explain E0277`.