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
|
@ -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`
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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."),
|
||||
}
|
||||
|
|
|
@ -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()];
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
self.consume_operand(location, operand);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(op, _) => {
|
||||
self.consume_operand(location, op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 { .. }
|
||||
|
|
|
@ -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(_) => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.)
|
||||
|
|
|
@ -728,6 +728,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(..) => {
|
||||
// Unsafe binders are always trivial to create.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -202,7 +202,8 @@ where
|
|||
| mir::Rvalue::NullaryOp(..)
|
||||
| mir::Rvalue::UnaryOp(..)
|
||||
| mir::Rvalue::Discriminant(..)
|
||||
| mir::Rvalue::Aggregate(..) => {}
|
||||
| mir::Rvalue::Aggregate(..)
|
||||
| mir::Rvalue::WrapUnsafeBinder(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())?,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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: _,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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 { .. }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -97,7 +97,8 @@ where
|
|||
| Rvalue::UnaryOp(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::Aggregate(..)
|
||||
| Rvalue::CopyForDeref(..) => {}
|
||||
| Rvalue::CopyForDeref(..)
|
||||
| Rvalue::WrapUnsafeBinder(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -575,6 +575,9 @@ impl WriteInfo {
|
|||
self.add_operand(op);
|
||||
}
|
||||
}
|
||||
Rvalue::WrapUnsafeBinder(op, _) => {
|
||||
self.add_operand(op);
|
||||
}
|
||||
Rvalue::ThreadLocalRef(_)
|
||||
| Rvalue::NullaryOp(_, _)
|
||||
| Rvalue::Ref(_, _, _)
|
||||
|
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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):"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2152,7 +2152,6 @@ symbols! {
|
|||
unwrap,
|
||||
unwrap_binder,
|
||||
unwrap_or,
|
||||
unwrap_unsafe_binder,
|
||||
use_extern_macros,
|
||||
use_nested_groups,
|
||||
used,
|
||||
|
|
|
@ -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, _) => {
|
||||
|
|
|
@ -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 { .. }
|
||||
|
|
|
@ -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(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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`.
|
||||
|
|
41
tests/ui/unsafe-binders/moves.rs
Normal file
41
tests/ui/unsafe-binders/moves.rs
Normal 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() {}
|
85
tests/ui/unsafe-binders/moves.stderr
Normal file
85
tests/ui/unsafe-binders/moves.stderr
Normal 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`.
|
Loading…
Add table
Add a link
Reference in a new issue