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
|
/// 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(_) => {
|
||||||
|
|
|
@ -925,6 +925,10 @@ fn codegen_stmt<'tcx>(
|
||||||
}
|
}
|
||||||
crate::discriminant::codegen_set_discriminant(fx, lval, variant_index);
|
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(_)
|
StatementKind::StorageLive(_)
|
||||||
|
@ -993,7 +997,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.)
|
||||||
|
|
|
@ -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())
|
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,13 @@ 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) => {
|
||||||
|
// 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));
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1276,6 +1276,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.
|
||||||
|
@ -1493,6 +1497,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,
|
||||||
|
|
|
@ -477,6 +477,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) => {
|
||||||
|
|
|
@ -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);
|
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::RawPtr(_, _)
|
||||||
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
|
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
|
||||||
| Rvalue::Discriminant(_) => {}
|
| 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);
|
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):"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2152,7 +2152,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,
|
||||||
|
|
|
@ -830,8 +830,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
||||||
// Let the visitor iterate into the argument/return
|
// Let the visitor iterate into the argument/return
|
||||||
// types appearing in the fn signature.
|
// types appearing in the fn signature.
|
||||||
}
|
}
|
||||||
ty::UnsafeBinder(_) => {
|
ty::UnsafeBinder(ty) => {
|
||||||
// FIXME(unsafe_binders): We should also recurse into the binder here.
|
// 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, _) => {
|
ty::Dynamic(data, r, _) => {
|
||||||
|
|
|
@ -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 { .. }
|
||||||
|
|
|
@ -116,6 +116,7 @@ fn check_rvalue<'tcx>(
|
||||||
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
|
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
|
||||||
Rvalue::Repeat(operand, _)
|
Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::Use(operand)
|
| Rvalue::Use(operand)
|
||||||
|
| Rvalue::WrapUnsafeBinder(operand, _)
|
||||||
| Rvalue::Cast(
|
| Rvalue::Cast(
|
||||||
CastKind::PointerWithExposedProvenance
|
CastKind::PointerWithExposedProvenance
|
||||||
| CastKind::IntToInt
|
| CastKind::IntToInt
|
||||||
|
@ -289,7 +290,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`.
|
||||||
|
|
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