Implement MIR, CTFE, and codegen for unsafe binders
This commit is contained in:
parent
7f36543a48
commit
fc1a9186dc
55 changed files with 493 additions and 101 deletions
|
@ -1657,7 +1657,7 @@ impl GenBlockKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether we're unwrapping or wrapping an unsafe binder
|
/// 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)]
|
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum UnsafeBinderCastKind {
|
pub enum UnsafeBinderCastKind {
|
||||||
// e.g. `&i32` -> `unsafe<'a> &'a i32`
|
// e.g. `&i32` -> `unsafe<'a> &'a i32`
|
||||||
|
|
|
@ -3915,7 +3915,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
ProjectionElem::ConstantIndex { .. }
|
ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Subtype(_)
|
| ProjectionElem::Subtype(_)
|
||||||
| ProjectionElem::Index(_) => kind,
|
| ProjectionElem::Index(_)
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => kind,
|
||||||
},
|
},
|
||||||
place_ty.projection_ty(tcx, elem),
|
place_ty.projection_ty(tcx, elem),
|
||||||
)
|
)
|
||||||
|
|
|
@ -370,6 +370,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
ProjectionElem::Downcast(..) => (),
|
ProjectionElem::Downcast(..) => (),
|
||||||
ProjectionElem::OpaqueCast(..) => (),
|
ProjectionElem::OpaqueCast(..) => (),
|
||||||
ProjectionElem::Subtype(..) => (),
|
ProjectionElem::Subtype(..) => (),
|
||||||
|
ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
||||||
ProjectionElem::Field(field, _ty) => {
|
ProjectionElem::Field(field, _ty) => {
|
||||||
// FIXME(project-rfc_2229#36): print capture precisely here.
|
// FIXME(project-rfc_2229#36): print capture precisely here.
|
||||||
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
|
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)
|
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
|
||||||
}
|
}
|
||||||
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
|
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
|
||||||
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
|
ProjectionElem::Subtype(ty)
|
||||||
PlaceTy::from_ty(*ty)
|
| ProjectionElem::OpaqueCast(ty)
|
||||||
}
|
| ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
|
||||||
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
|
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -167,7 +167,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::OpaqueCast { .. }
|
| ProjectionElem::OpaqueCast { .. }
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Downcast(..),
|
| ProjectionElem::Downcast(..)
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_),
|
||||||
],
|
],
|
||||||
} => bug!("Unexpected immutable place."),
|
} => bug!("Unexpected immutable place."),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1398,6 +1398,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
self.consume_operand(location, (operand, span), state);
|
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.
|
// So it's safe to skip these.
|
||||||
ProjectionElem::OpaqueCast(_)
|
ProjectionElem::OpaqueCast(_)
|
||||||
| ProjectionElem::Subtype(_)
|
| ProjectionElem::Subtype(_)
|
||||||
| ProjectionElem::Downcast(_, _) => (),
|
| ProjectionElem::Downcast(_, _)
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
place_ty = place_ty.projection_ty(tcx, elem);
|
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?
|
// 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
|
// assigning to (*P) requires P to be initialized
|
||||||
ProjectionElem::Deref => {
|
ProjectionElem::Deref => {
|
||||||
self.check_if_full_path_is_moved(
|
self.check_if_full_path_is_moved(
|
||||||
|
@ -2384,7 +2393,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Subtype(..)
|
| ProjectionElem::Subtype(..)
|
||||||
| ProjectionElem::OpaqueCast { .. }
|
| ProjectionElem::OpaqueCast { .. }
|
||||||
| ProjectionElem::Downcast(..) => {
|
| ProjectionElem::Downcast(..)
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||||
let upvar_field_projection = self.is_upvar_field_projection(place);
|
let upvar_field_projection = self.is_upvar_field_projection(place);
|
||||||
if let Some(field) = upvar_field_projection {
|
if let Some(field) = upvar_field_projection {
|
||||||
let upvar = &self.upvars[field.index()];
|
let upvar = &self.upvars[field.index()];
|
||||||
|
|
|
@ -250,7 +250,8 @@ fn place_components_conflict<'tcx>(
|
||||||
| (ProjectionElem::Subslice { .. }, _, _)
|
| (ProjectionElem::Subslice { .. }, _, _)
|
||||||
| (ProjectionElem::OpaqueCast { .. }, _, _)
|
| (ProjectionElem::OpaqueCast { .. }, _, _)
|
||||||
| (ProjectionElem::Subtype(_), _, _)
|
| (ProjectionElem::Subtype(_), _, _)
|
||||||
| (ProjectionElem::Downcast { .. }, _, _) => {
|
| (ProjectionElem::Downcast { .. }, _, _)
|
||||||
|
| (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {
|
||||||
// Recursive case. This can still be disjoint on a
|
// Recursive case. This can still be disjoint on a
|
||||||
// further iteration if this a shallow access and
|
// further iteration if this a shallow access and
|
||||||
// there's a deref later on, e.g., a borrow
|
// there's a deref later on, e.g., a borrow
|
||||||
|
@ -519,5 +520,9 @@ fn place_projection_conflict<'tcx>(
|
||||||
pi1_elem,
|
pi1_elem,
|
||||||
pi2_elem
|
pi2_elem
|
||||||
),
|
),
|
||||||
|
|
||||||
|
(ProjectionElem::UnwrapUnsafeBinder(_), _) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
self.consume_operand(location, operand);
|
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);
|
self.next = Some(cursor_base);
|
||||||
return Some(cursor);
|
return Some(cursor);
|
||||||
}
|
}
|
||||||
|
ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||||
|
self.next = Some(cursor_base);
|
||||||
|
return Some(cursor);
|
||||||
|
}
|
||||||
ProjectionElem::Downcast(..)
|
ProjectionElem::Downcast(..)
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::OpaqueCast { .. }
|
| ProjectionElem::OpaqueCast { .. }
|
||||||
|
|
|
@ -302,6 +302,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.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(_) => {
|
ProjectionElem::Subtype(_) => {
|
||||||
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
|
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
|
||||||
}
|
}
|
||||||
|
@ -2233,6 +2252,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
self.check_operand(right, location);
|
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::RawPtr(..)
|
||||||
| Rvalue::ThreadLocalRef(..)
|
| Rvalue::ThreadLocalRef(..)
|
||||||
| Rvalue::Len(..)
|
| Rvalue::Len(..)
|
||||||
|
@ -2258,7 +2298,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
| Rvalue::NullaryOp(..)
|
| Rvalue::NullaryOp(..)
|
||||||
| Rvalue::CopyForDeref(..)
|
| Rvalue::CopyForDeref(..)
|
||||||
| Rvalue::UnaryOp(..)
|
| Rvalue::UnaryOp(..)
|
||||||
| Rvalue::Discriminant(..) => None,
|
| Rvalue::Discriminant(..)
|
||||||
|
| Rvalue::WrapUnsafeBinder(..) => None,
|
||||||
|
|
||||||
Rvalue::Aggregate(aggregate, _) => match **aggregate {
|
Rvalue::Aggregate(aggregate, _) => match **aggregate {
|
||||||
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
|
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
|
||||||
|
@ -2450,7 +2491,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
| ProjectionElem::OpaqueCast(..)
|
| ProjectionElem::OpaqueCast(..)
|
||||||
| ProjectionElem::Index(..)
|
| ProjectionElem::Index(..)
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Subslice { .. } => {
|
| ProjectionElem::Subslice { .. }
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||||
// other field access
|
// other field access
|
||||||
}
|
}
|
||||||
ProjectionElem::Subtype(_) => {
|
ProjectionElem::Subtype(_) => {
|
||||||
|
|
|
@ -983,7 +983,9 @@ pub(crate) fn codegen_place<'tcx>(
|
||||||
cplace = cplace.place_deref(fx);
|
cplace = cplace.place_deref(fx);
|
||||||
}
|
}
|
||||||
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
|
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) => {
|
PlaceElem::Field(field, _ty) => {
|
||||||
cplace = cplace.place_field(fx, field);
|
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")
|
bug!("encountered OpaqueCast({ty}) in codegen")
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
|
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) => {
|
mir::ProjectionElem::Index(index) => {
|
||||||
let index = &mir::Operand::Copy(mir::Place::from(index));
|
let index = &mir::Operand::Copy(mir::Place::from(index));
|
||||||
let index = self.codegen_operand(bx, 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 }
|
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::Discriminant(..) |
|
||||||
mir::Rvalue::NullaryOp(..) |
|
mir::Rvalue::NullaryOp(..) |
|
||||||
mir::Rvalue::ThreadLocalRef(_) |
|
mir::Rvalue::ThreadLocalRef(_) |
|
||||||
mir::Rvalue::Use(..) => // (*)
|
mir::Rvalue::Use(..) |
|
||||||
|
mir::Rvalue::WrapUnsafeBinder(..) => // (*)
|
||||||
true,
|
true,
|
||||||
// Arrays are always aggregates, so it's not worth checking anything here.
|
// 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.)
|
// (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
|
||||||
|
|
|
@ -723,6 +723,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())
|
in_place::<Q, _>(cx, in_local, place.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rvalue::WrapUnsafeBinder(op, _) => in_operand::<Q, _>(cx, in_local, op),
|
||||||
|
|
||||||
Rvalue::Aggregate(kind, operands) => {
|
Rvalue::Aggregate(kind, operands) => {
|
||||||
// Return early if we know that the struct or enum being constructed is always
|
// Return early if we know that the struct or enum being constructed is always
|
||||||
// qualified.
|
// qualified.
|
||||||
|
@ -297,7 +299,8 @@ where
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Downcast(_, _)
|
| ProjectionElem::Downcast(_, _)
|
||||||
| ProjectionElem::Index(_) => {}
|
| ProjectionElem::Index(_)
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let base_ty = place_base.ty(cx.body, cx.tcx);
|
let base_ty = place_base.ty(cx.body, cx.tcx);
|
||||||
|
|
|
@ -202,7 +202,8 @@ where
|
||||||
| mir::Rvalue::NullaryOp(..)
|
| mir::Rvalue::NullaryOp(..)
|
||||||
| mir::Rvalue::UnaryOp(..)
|
| mir::Rvalue::UnaryOp(..)
|
||||||
| mir::Rvalue::Discriminant(..)
|
| mir::Rvalue::Discriminant(..)
|
||||||
| mir::Rvalue::Aggregate(..) => {}
|
| mir::Rvalue::Aggregate(..)
|
||||||
|
| mir::Rvalue::WrapUnsafeBinder(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -381,6 +381,7 @@ where
|
||||||
OpaqueCast(ty) => {
|
OpaqueCast(ty) => {
|
||||||
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
|
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.
|
// We don't want anything happening here, this is here as a dummy.
|
||||||
Subtype(_) => base.transmute(base.layout(), self)?,
|
Subtype(_) => base.transmute(base.layout(), self)?,
|
||||||
Field(field, _) => self.project_field(base, field.index())?,
|
Field(field, _) => self.project_field(base, field.index())?,
|
||||||
|
|
|
@ -277,6 +277,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
|
let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
|
||||||
self.write_immediate(*discr, &dest)?;
|
self.write_immediate(*discr, &dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WrapUnsafeBinder(ref op, _ty) => {
|
||||||
|
let op = self.eval_operand(op, None)?;
|
||||||
|
self.copy_op_allow_transmute(&op, &dest)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("{:?}", self.dump_place(&dest));
|
trace!("{:?}", self.dump_place(&dest));
|
||||||
|
|
|
@ -1658,8 +1658,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
|
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
|
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
hir::UnsafeBinderCastKind::Wrap => {
|
hir::UnsafeBinderCastKind::Wrap => {
|
||||||
let ascribed_ty =
|
let ascribed_ty =
|
||||||
|
|
|
@ -1248,6 +1248,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||||
ShallowInitBox(ref place, ref ty) => {
|
ShallowInitBox(ref place, ref ty) => {
|
||||||
with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {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::Index(_)
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Subslice { .. } => {}
|
| 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 } => {
|
ProjectionElem::Subslice { from, to, from_end: false } => {
|
||||||
write!(fmt, "[{from:?}..{to:?}]")?;
|
write!(fmt, "[{from:?}..{to:?}]")?;
|
||||||
}
|
}
|
||||||
|
ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||||
|
write!(fmt, "; {ty})")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,8 @@ impl<V, T> ProjectionElem<V, T> {
|
||||||
| Self::Subtype(_)
|
| Self::Subtype(_)
|
||||||
| Self::ConstantIndex { .. }
|
| Self::ConstantIndex { .. }
|
||||||
| Self::Subslice { .. }
|
| Self::Subslice { .. }
|
||||||
| Self::Downcast(_, _) => false,
|
| Self::Downcast(_, _)
|
||||||
|
| Self::UnwrapUnsafeBinder(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +77,8 @@ impl<V, T> ProjectionElem<V, T> {
|
||||||
| Self::Subtype(_)
|
| Self::Subtype(_)
|
||||||
| Self::ConstantIndex { .. }
|
| Self::ConstantIndex { .. }
|
||||||
| Self::Subslice { .. }
|
| Self::Subslice { .. }
|
||||||
| Self::Downcast(_, _) => true,
|
| Self::Downcast(_, _)
|
||||||
|
| Self::UnwrapUnsafeBinder(..) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +104,9 @@ impl<V, T> ProjectionElem<V, T> {
|
||||||
| Self::Subtype(_)
|
| Self::Subtype(_)
|
||||||
| Self::OpaqueCast(_)
|
| Self::OpaqueCast(_)
|
||||||
| Self::Subslice { .. } => false,
|
| Self::Subslice { .. } => false,
|
||||||
|
|
||||||
|
// FIXME(unsafe_binders): Figure this out.
|
||||||
|
Self::UnwrapUnsafeBinder(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,7 +448,8 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
| Rvalue::UnaryOp(_, _)
|
| Rvalue::UnaryOp(_, _)
|
||||||
| Rvalue::Discriminant(_)
|
| Rvalue::Discriminant(_)
|
||||||
| Rvalue::Aggregate(_, _)
|
| Rvalue::Aggregate(_, _)
|
||||||
| Rvalue::ShallowInitBox(_, _) => true,
|
| Rvalue::ShallowInitBox(_, _)
|
||||||
|
| Rvalue::WrapUnsafeBinder(_, _) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1275,6 +1275,10 @@ pub enum ProjectionElem<V, T> {
|
||||||
/// requiring an intermediate variable.
|
/// requiring an intermediate variable.
|
||||||
OpaqueCast(T),
|
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
|
/// 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
|
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
|
||||||
/// explicit during optimizations and codegen.
|
/// explicit during optimizations and codegen.
|
||||||
|
@ -1492,6 +1496,9 @@ pub enum Rvalue<'tcx> {
|
||||||
/// optimizations and codegen backends that previously had to handle deref operations anywhere
|
/// optimizations and codegen backends that previously had to handle deref operations anywhere
|
||||||
/// in a place.
|
/// in a place.
|
||||||
CopyForDeref(Place<'tcx>),
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||||
|
|
|
@ -146,6 +146,11 @@ impl<'tcx> PlaceTy<'tcx> {
|
||||||
ProjectionElem::Subtype(ty) => {
|
ProjectionElem::Subtype(ty) => {
|
||||||
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, 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);
|
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
|
||||||
answer
|
answer
|
||||||
|
@ -241,6 +246,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
},
|
},
|
||||||
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
|
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
|
||||||
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, 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
|
//! `TypeFoldable` implementations for MIR types
|
||||||
|
|
||||||
use rustc_ast::InlineAsmTemplatePiece;
|
use rustc_ast::InlineAsmTemplatePiece;
|
||||||
|
use rustc_hir::UnsafeBinderCastKind;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -21,6 +22,7 @@ TrivialTypeTraversalImpls! {
|
||||||
SwitchTargets,
|
SwitchTargets,
|
||||||
CoroutineKind,
|
CoroutineKind,
|
||||||
CoroutineSavedLocal,
|
CoroutineSavedLocal,
|
||||||
|
UnsafeBinderCastKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
TrivialTypeTraversalImpls! {
|
TrivialTypeTraversalImpls! {
|
||||||
|
|
|
@ -781,6 +781,11 @@ macro_rules! make_mir_visitor {
|
||||||
self.visit_operand(operand, location);
|
self.visit_operand(operand, location);
|
||||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(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));
|
self.visit_ty(&mut new_ty, TyContext::Location(location));
|
||||||
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
|
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::Deref
|
||||||
| PlaceElem::ConstantIndex { .. }
|
| PlaceElem::ConstantIndex { .. }
|
||||||
| PlaceElem::Subslice { .. }
|
| PlaceElem::Subslice { .. }
|
||||||
|
@ -1219,7 +1229,8 @@ macro_rules! visit_place_fns {
|
||||||
match elem {
|
match elem {
|
||||||
ProjectionElem::OpaqueCast(ty)
|
ProjectionElem::OpaqueCast(ty)
|
||||||
| ProjectionElem::Subtype(ty)
|
| ProjectionElem::Subtype(ty)
|
||||||
| ProjectionElem::Field(_, ty) => {
|
| ProjectionElem::Field(_, ty)
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||||
self.visit_ty(ty, TyContext::Location(location));
|
self.visit_ty(ty, TyContext::Location(location));
|
||||||
}
|
}
|
||||||
ProjectionElem::Index(local) => {
|
ProjectionElem::Index(local) => {
|
||||||
|
|
|
@ -489,6 +489,19 @@ pub enum ExprKind<'tcx> {
|
||||||
user_ty: UserTy<'tcx>,
|
user_ty: UserTy<'tcx>,
|
||||||
user_ty_span: Span,
|
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.
|
/// A closure definition.
|
||||||
Closure(Box<ClosureExpr<'tcx>>),
|
Closure(Box<ClosureExpr<'tcx>>),
|
||||||
/// A literal.
|
/// A literal.
|
||||||
|
|
|
@ -136,6 +136,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
||||||
| ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
|
| ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
|
||||||
visitor.visit_expr(&visitor.thir()[source])
|
visitor.visit_expr(&visitor.thir()[source])
|
||||||
}
|
}
|
||||||
|
PlaceUnwrapUnsafeBinder { source }
|
||||||
|
| ValueUnwrapUnsafeBinder { source }
|
||||||
|
| WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]),
|
||||||
Closure(box ClosureExpr {
|
Closure(box ClosureExpr {
|
||||||
closure_id: _,
|
closure_id: _,
|
||||||
args: _,
|
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
|
.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
|
.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 =
|
mir_build_unsafe_field_requires_unsafe =
|
||||||
use of unsafe field is unsafe and requires unsafe block
|
use of unsafe field is unsafe and requires unsafe block
|
||||||
.note = unsafe fields may carry library invariants
|
.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::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
|
||||||
ProjectionElem::Index(..)
|
ProjectionElem::Index(..)
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Subslice { .. } => {
|
| ProjectionElem::Subslice { .. }
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||||
// We don't capture array-access projections.
|
// We don't capture array-access projections.
|
||||||
// We can stop here as arrays are captured completely.
|
// We can stop here as arrays are captured completely.
|
||||||
break;
|
break;
|
||||||
|
@ -523,6 +524,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block.and(PlaceBuilder::from(temp))
|
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::Array { .. }
|
||||||
| ExprKind::Tuple { .. }
|
| ExprKind::Tuple { .. }
|
||||||
| ExprKind::Adt { .. }
|
| ExprKind::Adt { .. }
|
||||||
|
@ -560,7 +575,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::OffsetOf { .. }
|
| ExprKind::OffsetOf { .. }
|
||||||
| ExprKind::Yield { .. }
|
| ExprKind::Yield { .. }
|
||||||
| ExprKind::ThreadLocalRef(_)
|
| ExprKind::ThreadLocalRef(_)
|
||||||
| ExprKind::Call { .. } => {
|
| ExprKind::Call { .. }
|
||||||
|
| ExprKind::WrapUnsafeBinder { .. } => {
|
||||||
// these are not places, so we need to make a temporary.
|
// these are not places, so we need to make a temporary.
|
||||||
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
|
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
|
||||||
let temp =
|
let temp =
|
||||||
|
@ -776,7 +792,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ProjectionElem::OpaqueCast(..)
|
| ProjectionElem::OpaqueCast(..)
|
||||||
| ProjectionElem::Subtype(..)
|
| ProjectionElem::Subtype(..)
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
| 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))))
|
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::Yield { .. }
|
||||||
| ExprKind::Block { .. }
|
| ExprKind::Block { .. }
|
||||||
| ExprKind::Match { .. }
|
| ExprKind::Match { .. }
|
||||||
|
@ -532,7 +545,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::Become { .. }
|
| ExprKind::Become { .. }
|
||||||
| ExprKind::InlineAsm { .. }
|
| ExprKind::InlineAsm { .. }
|
||||||
| ExprKind::PlaceTypeAscription { .. }
|
| ExprKind::PlaceTypeAscription { .. }
|
||||||
| ExprKind::ValueTypeAscription { .. } => {
|
| ExprKind::ValueTypeAscription { .. }
|
||||||
|
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
|
||||||
|
| ExprKind::ValueUnwrapUnsafeBinder { .. } => {
|
||||||
// these do not have corresponding `Rvalue` variants,
|
// these do not have corresponding `Rvalue` variants,
|
||||||
// so make an operand and then return that
|
// so make an operand and then return that
|
||||||
debug_assert!(!matches!(
|
debug_assert!(!matches!(
|
||||||
|
|
|
@ -41,7 +41,9 @@ impl Category {
|
||||||
| ExprKind::UpvarRef { .. }
|
| ExprKind::UpvarRef { .. }
|
||||||
| ExprKind::VarRef { .. }
|
| ExprKind::VarRef { .. }
|
||||||
| ExprKind::PlaceTypeAscription { .. }
|
| ExprKind::PlaceTypeAscription { .. }
|
||||||
| ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
|
| ExprKind::ValueTypeAscription { .. }
|
||||||
|
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
|
||||||
|
| ExprKind::ValueUnwrapUnsafeBinder { .. } => Some(Category::Place),
|
||||||
|
|
||||||
ExprKind::LogicalOp { .. }
|
ExprKind::LogicalOp { .. }
|
||||||
| ExprKind::Match { .. }
|
| ExprKind::Match { .. }
|
||||||
|
@ -68,7 +70,8 @@ impl Category {
|
||||||
| ExprKind::Assign { .. }
|
| ExprKind::Assign { .. }
|
||||||
| ExprKind::AssignOp { .. }
|
| ExprKind::AssignOp { .. }
|
||||||
| ExprKind::ThreadLocalRef(_)
|
| ExprKind::ThreadLocalRef(_)
|
||||||
| ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
|
| ExprKind::OffsetOf { .. }
|
||||||
|
| ExprKind::WrapUnsafeBinder { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
|
||||||
|
|
||||||
ExprKind::ConstBlock { .. }
|
ExprKind::ConstBlock { .. }
|
||||||
| ExprKind::Literal { .. }
|
| ExprKind::Literal { .. }
|
||||||
|
|
|
@ -554,7 +554,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ExprKind::VarRef { .. }
|
ExprKind::VarRef { .. }
|
||||||
| ExprKind::UpvarRef { .. }
|
| ExprKind::UpvarRef { .. }
|
||||||
| ExprKind::PlaceTypeAscription { .. }
|
| ExprKind::PlaceTypeAscription { .. }
|
||||||
| ExprKind::ValueTypeAscription { .. } => {
|
| ExprKind::ValueTypeAscription { .. }
|
||||||
|
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
|
||||||
|
| ExprKind::ValueUnwrapUnsafeBinder { .. } => {
|
||||||
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
|
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
|
||||||
|
|
||||||
let place = unpack!(block = this.as_place(block, expr_id));
|
let place = unpack!(block = this.as_place(block, expr_id));
|
||||||
|
@ -613,7 +615,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::ConstParam { .. }
|
| ExprKind::ConstParam { .. }
|
||||||
| ExprKind::ThreadLocalRef(_)
|
| ExprKind::ThreadLocalRef(_)
|
||||||
| ExprKind::StaticRef { .. }
|
| ExprKind::StaticRef { .. }
|
||||||
| ExprKind::OffsetOf { .. } => {
|
| ExprKind::OffsetOf { .. }
|
||||||
|
| ExprKind::WrapUnsafeBinder { .. } => {
|
||||||
debug_assert!(match Category::of(&expr.kind).unwrap() {
|
debug_assert!(match Category::of(&expr.kind).unwrap() {
|
||||||
// should be handled above
|
// should be handled above
|
||||||
Category::Rvalue(RvalueFunc::Into) => false,
|
Category::Rvalue(RvalueFunc::Into) => false,
|
||||||
|
|
|
@ -439,6 +439,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
| ExprKind::NeverToAny { .. }
|
| ExprKind::NeverToAny { .. }
|
||||||
| ExprKind::PlaceTypeAscription { .. }
|
| ExprKind::PlaceTypeAscription { .. }
|
||||||
| ExprKind::ValueTypeAscription { .. }
|
| ExprKind::ValueTypeAscription { .. }
|
||||||
|
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
|
||||||
|
| ExprKind::ValueUnwrapUnsafeBinder { .. }
|
||||||
|
| ExprKind::WrapUnsafeBinder { .. }
|
||||||
| ExprKind::PointerCoercion { .. }
|
| ExprKind::PointerCoercion { .. }
|
||||||
| ExprKind::Repeat { .. }
|
| ExprKind::Repeat { .. }
|
||||||
| ExprKind::StaticRef { .. }
|
| 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);
|
visit::walk_expr(self, expr);
|
||||||
|
@ -728,6 +736,7 @@ enum UnsafeOpKind {
|
||||||
/// (e.g., with `-C target-feature`).
|
/// (e.g., with `-C target-feature`).
|
||||||
build_enabled: Vec<Symbol>,
|
build_enabled: Vec<Symbol>,
|
||||||
},
|
},
|
||||||
|
UnsafeBinderCast,
|
||||||
}
|
}
|
||||||
|
|
||||||
use UnsafeOpKind::*;
|
use UnsafeOpKind::*;
|
||||||
|
@ -891,6 +900,15 @@ impl UnsafeOpKind {
|
||||||
unsafe_not_inherited_note,
|
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),
|
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>,
|
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)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)]
|
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)]
|
||||||
#[help]
|
#[help]
|
||||||
|
@ -494,6 +506,32 @@ pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
|
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)]
|
#[derive(Subdiagnostic)]
|
||||||
#[label(mir_build_unsafe_not_inherited)]
|
#[label(mir_build_unsafe_not_inherited)]
|
||||||
pub(crate) struct UnsafeNotInheritedNote {
|
pub(crate) struct UnsafeNotInheritedNote {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||||
|
use rustc_ast::UnsafeBinderCastKind;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||||
|
@ -910,8 +911,19 @@ impl<'tcx> Cx<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
|
hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, source, _ty) => {
|
||||||
unreachable!("unsafe binders are not yet implemented")
|
// 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) },
|
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
|
||||||
|
|
|
@ -326,9 +326,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||||
| Use { source }
|
| Use { source }
|
||||||
| PointerCoercion { source, .. }
|
| PointerCoercion { source, .. }
|
||||||
| PlaceTypeAscription { source, .. }
|
| PlaceTypeAscription { source, .. }
|
||||||
| ValueTypeAscription { source, .. } => {
|
| ValueTypeAscription { source, .. }
|
||||||
self.is_known_valid_scrutinee(&self.thir()[*source])
|
| PlaceUnwrapUnsafeBinder { source }
|
||||||
}
|
| ValueUnwrapUnsafeBinder { source }
|
||||||
|
| WrapUnsafeBinder { source } => self.is_known_valid_scrutinee(&self.thir()[*source]),
|
||||||
|
|
||||||
// These diverge.
|
// These diverge.
|
||||||
Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true,
|
Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true,
|
||||||
|
|
|
@ -475,6 +475,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
||||||
self.print_expr(*source, depth_lvl + 2);
|
self.print_expr(*source, depth_lvl + 2);
|
||||||
print_indented!(self, "}", depth_lvl);
|
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) => {
|
Closure(closure_expr) => {
|
||||||
print_indented!(self, "Closure {", depth_lvl);
|
print_indented!(self, "Closure {", depth_lvl);
|
||||||
print_indented!(self, "closure_expr:", depth_lvl + 1);
|
print_indented!(self, "closure_expr:", depth_lvl + 1);
|
||||||
|
|
|
@ -97,7 +97,8 @@ where
|
||||||
| Rvalue::UnaryOp(..)
|
| Rvalue::UnaryOp(..)
|
||||||
| Rvalue::Discriminant(..)
|
| Rvalue::Discriminant(..)
|
||||||
| Rvalue::Aggregate(..)
|
| 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::Downcast(a, u) => ProjectionElem::Downcast(a, u),
|
||||||
ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()),
|
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::Infer(_)
|
||||||
| ty::Error(_)
|
| ty::Error(_)
|
||||||
| ty::Placeholder(_) => bug!(
|
| 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 { .. } => {
|
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:#?}"),
|
_ => bug!("Unexpected type {place_ty:#?}"),
|
||||||
},
|
},
|
||||||
|
ProjectionElem::UnwrapUnsafeBinder(_) => {}
|
||||||
// `OpaqueCast`:Only transmutes the type, so no moves there.
|
// `OpaqueCast`:Only transmutes the type, so no moves there.
|
||||||
// `Downcast` :Only changes information about a `Place` without moving.
|
// `Downcast` :Only changes information about a `Place` without moving.
|
||||||
// `Subtype` :Only transmutes the type, so moves.
|
// `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::Repeat(ref operand, _)
|
||||||
| Rvalue::Cast(_, ref operand, _)
|
| Rvalue::Cast(_, ref operand, _)
|
||||||
| Rvalue::ShallowInitBox(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)) => {
|
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
|
||||||
self.gather_operand(lhs);
|
self.gather_operand(lhs);
|
||||||
self.gather_operand(rhs);
|
self.gather_operand(rhs);
|
||||||
|
|
|
@ -504,7 +504,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
||||||
| Rvalue::Cast(..)
|
| Rvalue::Cast(..)
|
||||||
| Rvalue::BinaryOp(..)
|
| Rvalue::BinaryOp(..)
|
||||||
| Rvalue::Aggregate(..)
|
| Rvalue::Aggregate(..)
|
||||||
| Rvalue::ShallowInitBox(..) => {
|
| Rvalue::ShallowInitBox(..)
|
||||||
|
| Rvalue::WrapUnsafeBinder(..) => {
|
||||||
// No modification is possible through these r-values.
|
// No modification is possible through these r-values.
|
||||||
return ValueOrPlace::TOP;
|
return ValueOrPlace::TOP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -575,6 +575,9 @@ impl WriteInfo {
|
||||||
self.add_operand(op);
|
self.add_operand(op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Rvalue::WrapUnsafeBinder(op, _) => {
|
||||||
|
self.add_operand(op);
|
||||||
|
}
|
||||||
Rvalue::ThreadLocalRef(_)
|
Rvalue::ThreadLocalRef(_)
|
||||||
| Rvalue::NullaryOp(_, _)
|
| Rvalue::NullaryOp(_, _)
|
||||||
| Rvalue::Ref(_, _, _)
|
| Rvalue::Ref(_, _, _)
|
||||||
|
|
|
@ -476,6 +476,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||||
}
|
}
|
||||||
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
|
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
|
||||||
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
|
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
|
||||||
|
ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||||
|
ProjectionElem::UnwrapUnsafeBinder(ty)
|
||||||
|
}
|
||||||
// This should have been replaced by a `ConstantIndex` earlier.
|
// This should have been replaced by a `ConstantIndex` earlier.
|
||||||
ProjectionElem::Index(_) => return None,
|
ProjectionElem::Index(_) => return None,
|
||||||
};
|
};
|
||||||
|
@ -713,6 +716,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||||
}
|
}
|
||||||
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
|
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
|
||||||
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
|
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
|
||||||
|
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(self.insert(Value::Projection(value, proj)))
|
Some(self.insert(Value::Projection(value, proj)))
|
||||||
|
@ -867,6 +871,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||||
self.simplify_place_projection(place, location);
|
self.simplify_place_projection(place, location);
|
||||||
return self.new_pointer(*place, AddressKind::Address(mutbl));
|
return self.new_pointer(*place, AddressKind::Address(mutbl));
|
||||||
}
|
}
|
||||||
|
Rvalue::WrapUnsafeBinder(ref mut op, _) => {
|
||||||
|
return self.simplify_operand(op, location);
|
||||||
|
}
|
||||||
|
|
||||||
// Operations.
|
// Operations.
|
||||||
Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
|
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::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
|
||||||
ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
|
ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
|
||||||
ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(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::Cast(..)
|
||||||
| Rvalue::ShallowInitBox(..)
|
| Rvalue::ShallowInitBox(..)
|
||||||
| Rvalue::Discriminant(..)
|
| Rvalue::Discriminant(..)
|
||||||
| Rvalue::NullaryOp(..) => {}
|
| Rvalue::NullaryOp(..)
|
||||||
|
| Rvalue::WrapUnsafeBinder(..) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME we need to revisit this for #67176
|
// FIXME we need to revisit this for #67176
|
||||||
|
@ -546,7 +547,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
let val: Value<'_> = match *rvalue {
|
let val: Value<'_> = match *rvalue {
|
||||||
ThreadLocalRef(_) => return None,
|
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(),
|
CopyForDeref(place) => self.eval_place(place)?.into(),
|
||||||
|
|
||||||
|
|
|
@ -293,7 +293,8 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
// Recurse directly.
|
// Recurse directly.
|
||||||
ProjectionElem::ConstantIndex { .. }
|
ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Subtype(_)
|
| ProjectionElem::Subtype(_)
|
||||||
| ProjectionElem::Subslice { .. } => {}
|
| ProjectionElem::Subslice { .. }
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
|
||||||
|
|
||||||
// Never recurse.
|
// Never recurse.
|
||||||
ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
|
ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
|
||||||
|
@ -426,7 +427,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
|
|
||||||
fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
|
fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
|
Rvalue::Use(operand)
|
||||||
|
| Rvalue::Repeat(operand, _)
|
||||||
|
| Rvalue::WrapUnsafeBinder(operand, _) => {
|
||||||
self.validate_operand(operand)?;
|
self.validate_operand(operand)?;
|
||||||
}
|
}
|
||||||
Rvalue::CopyForDeref(place) => {
|
Rvalue::CopyForDeref(place) => {
|
||||||
|
|
|
@ -1361,7 +1361,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
| Rvalue::ThreadLocalRef(_)
|
| Rvalue::ThreadLocalRef(_)
|
||||||
| Rvalue::RawPtr(_, _)
|
| Rvalue::RawPtr(_, _)
|
||||||
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
|
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
|
||||||
| Rvalue::Discriminant(_) => {}
|
| Rvalue::Discriminant(_)
|
||||||
|
| Rvalue::WrapUnsafeBinder(..) => {}
|
||||||
}
|
}
|
||||||
self.super_rvalue(rvalue, location);
|
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))
|
stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
|
||||||
}
|
}
|
||||||
CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.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)),
|
Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
|
||||||
OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
|
OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
|
||||||
Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
|
Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
|
||||||
|
UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2151,7 +2151,6 @@ symbols! {
|
||||||
unwrap,
|
unwrap,
|
||||||
unwrap_binder,
|
unwrap_binder,
|
||||||
unwrap_or,
|
unwrap_or,
|
||||||
unwrap_unsafe_binder,
|
|
||||||
use_extern_macros,
|
use_extern_macros,
|
||||||
use_nested_groups,
|
use_nested_groups,
|
||||||
used,
|
used,
|
||||||
|
|
|
@ -116,6 +116,11 @@ fn recurse_build<'tcx>(
|
||||||
| &ExprKind::ValueTypeAscription { source, .. } => {
|
| &ExprKind::ValueTypeAscription { source, .. } => {
|
||||||
recurse_build(tcx, body, source, root_span)?
|
recurse_build(tcx, body, source, root_span)?
|
||||||
}
|
}
|
||||||
|
&ExprKind::PlaceUnwrapUnsafeBinder { .. }
|
||||||
|
| &ExprKind::ValueUnwrapUnsafeBinder { .. }
|
||||||
|
| &ExprKind::WrapUnsafeBinder { .. } => {
|
||||||
|
todo!("FIXME(unsafe_binders)")
|
||||||
|
}
|
||||||
&ExprKind::Literal { lit, neg } => {
|
&ExprKind::Literal { lit, neg } => {
|
||||||
let sp = node.span;
|
let sp = node.span;
|
||||||
tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg })
|
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::Adt(_)
|
||||||
| thir::ExprKind::PlaceTypeAscription { .. }
|
| thir::ExprKind::PlaceTypeAscription { .. }
|
||||||
| thir::ExprKind::ValueTypeAscription { .. }
|
| thir::ExprKind::ValueTypeAscription { .. }
|
||||||
|
| thir::ExprKind::PlaceUnwrapUnsafeBinder { .. }
|
||||||
|
| thir::ExprKind::ValueUnwrapUnsafeBinder { .. }
|
||||||
|
| thir::ExprKind::WrapUnsafeBinder { .. }
|
||||||
| thir::ExprKind::Closure(_)
|
| thir::ExprKind::Closure(_)
|
||||||
| thir::ExprKind::Literal { .. }
|
| thir::ExprKind::Literal { .. }
|
||||||
| thir::ExprKind::NonHirLiteral { .. }
|
| thir::ExprKind::NonHirLiteral { .. }
|
||||||
|
|
|
@ -289,7 +289,8 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
|
||||||
| ProjectionElem::Downcast(..)
|
| ProjectionElem::Downcast(..)
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Subtype(_)
|
| ProjectionElem::Subtype(_)
|
||||||
| ProjectionElem::Index(_) => {},
|
| ProjectionElem::Index(_)
|
||||||
|
| ProjectionElem::UnwrapUnsafeBinder(_) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
#![feature(unsafe_binders)]
|
#![feature(unsafe_binders)]
|
||||||
//~^ WARN the feature `unsafe_binders` is incomplete
|
//~^ WARN the feature `unsafe_binders` is incomplete
|
||||||
|
|
||||||
|
@ -7,8 +9,6 @@ fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let x = 1;
|
let x = 1;
|
||||||
let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
|
let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
|
||||||
//~^ ERROR unsafe binder casts are not fully implemented
|
|
||||||
let rx = *unwrap_binder!(binder);
|
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
|
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)]
|
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: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
error: unsafe binder casts are not fully implemented
|
warning: 1 warning emitted
|
||||||
--> $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
|
|
||||||
|
|
||||||
|
|
|
@ -5,38 +5,31 @@ use std::unsafe_binder::{wrap_binder, unwrap_binder};
|
||||||
|
|
||||||
fn a() {
|
fn a() {
|
||||||
let _: unsafe<'a> &'a i32 = wrap_binder!(&());
|
let _: unsafe<'a> &'a i32 = wrap_binder!(&());
|
||||||
//~^ ERROR unsafe binder casts are not fully implemented
|
//~^ ERROR mismatched types
|
||||||
//~| ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn b() {
|
fn b() {
|
||||||
let _: i32 = wrap_binder!(&());
|
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() {
|
fn c() {
|
||||||
let y = 1;
|
let y = 1;
|
||||||
unwrap_binder!(y);
|
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() {
|
fn d() {
|
||||||
let unknown = Default::default();
|
let unknown = Default::default();
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
unwrap_binder!(unknown);
|
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() {
|
fn e() {
|
||||||
let x = wrap_binder!(&42);
|
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.
|
// Currently, type inference doesn't flow backwards for unsafe binders.
|
||||||
// It could, perhaps, but that may cause even more surprising corners.
|
// 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;
|
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: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= 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
|
error[E0308]: mismatched types
|
||||||
--> $DIR/mismatch.rs:7:46
|
--> $DIR/mismatch.rs:7:46
|
||||||
|
|
|
|
||||||
|
@ -22,14 +16,8 @@ LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&());
|
||||||
= note: expected reference `&i32`
|
= note: expected reference `&i32`
|
||||||
found reference `&()`
|
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`
|
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!(&());
|
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: 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)
|
= 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!()`
|
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);
|
LL | unwrap_binder!(y);
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: only an unsafe binder type can be unwrapped
|
= note: only an unsafe binder type can be unwrapped
|
||||||
|
|
||||||
error: unsafe binder casts are not fully implemented
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/mismatch.rs:27:20
|
--> $DIR/mismatch.rs:23:9
|
||||||
|
|
|
|
||||||
|
LL | let unknown = Default::default();
|
||||||
|
| ^^^^^^^
|
||||||
|
LL |
|
||||||
LL | unwrap_binder!(unknown);
|
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
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/mismatch.rs:34:26
|
--> $DIR/mismatch.rs:29:26
|
||||||
|
|
|
|
||||||
LL | let x = wrap_binder!(&42);
|
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`.
|
||||||
|
|
38
tests/ui/unsafe-binders/moves.rs
Normal file
38
tests/ui/unsafe-binders/moves.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#![feature(unsafe_binders)]
|
||||||
|
//~^ WARN the feature `unsafe_binders` is incomplete
|
||||||
|
|
||||||
|
use std::unsafe_binder::{wrap_binder, unwrap_binder};
|
||||||
|
use std::mem::drop;
|
||||||
|
|
||||||
|
struct NotCopy;
|
||||||
|
|
||||||
|
fn use_after_wrap() {
|
||||||
|
unsafe {
|
||||||
|
let base = NotCopy;
|
||||||
|
let binder: unsafe<> NotCopy = wrap_binder!(base);
|
||||||
|
drop(base);
|
||||||
|
//~^ 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));
|
||||||
|
//~^ 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);
|
||||||
|
//~^ ERROR use of moved value: `binder.0`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
53
tests/ui/unsafe-binders/moves.stderr
Normal file
53
tests/ui/unsafe-binders/moves.stderr
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/moves.rs:1: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[E0382]: use of moved value: `base`
|
||||||
|
--> $DIR/moves.rs:13:14
|
||||||
|
|
|
||||||
|
LL | let base = NotCopy;
|
||||||
|
| ---- move occurs because `base` has type `NotCopy`, which does not implement the `Copy` trait
|
||||||
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(base);
|
||||||
|
| ---- value moved here
|
||||||
|
LL | drop(base);
|
||||||
|
| ^^^^ value used here after move
|
||||||
|
|
|
||||||
|
note: if `NotCopy` implemented `Clone`, you could clone the value
|
||||||
|
--> $DIR/moves.rs:7:1
|
||||||
|
|
|
||||||
|
LL | struct NotCopy;
|
||||||
|
| ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
|
||||||
|
...
|
||||||
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(base);
|
||||||
|
| ---- you could clone this value
|
||||||
|
|
||||||
|
error[E0382]: use of moved value: `binder`
|
||||||
|
--> $DIR/moves.rs:22:14
|
||||||
|
|
|
||||||
|
LL | drop(unwrap_binder!(binder));
|
||||||
|
| ---------------------- value moved here
|
||||||
|
LL | drop(unwrap_binder!(binder));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^ value used here after move
|
||||||
|
|
|
||||||
|
= note: move occurs because `binder` has type `NotCopy`, which does not implement the `Copy` trait
|
||||||
|
= note: this error originates in the macro `unwrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0382]: use of moved value: `binder.0`
|
||||||
|
--> $DIR/moves.rs:33:14
|
||||||
|
|
|
||||||
|
LL | drop(unwrap_binder!(binder).0);
|
||||||
|
| ------------------------ value moved here
|
||||||
|
...
|
||||||
|
LL | drop(unwrap_binder!(binder).0);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move
|
||||||
|
|
|
||||||
|
= note: move occurs because `binder.0` has type `NotCopy`, which does not implement the `Copy` trait
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0382`.
|
Loading…
Add table
Add a link
Reference in a new issue